From 47dffcae855f3c2e0005c60ae3cae990a3504bd1 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Wed, 8 Aug 2012 00:08:37 +1000 Subject: [PATCH] Update to v090 release. byuu says: Most notably, this release adds Nintendo DS emulation. The Nintendo DS module was written entirely by Cydrak, so please give him all of the credit for it. I for one am extremely grateful to be allowed to use his module in bsnes. The Nintendo DS emulator's standalone name is dasShiny. You will need the Nintendo DS firmware, which I cannot provide, in order to use it. It also cannot (currently?) detect the save type used by NDS games. As such, manifest.xml files must be created manually for this purpose. The long-term plan is to create a database of save types for each game. Also, you will need an analog input device for the touch screen for now (joypad axes work well.) There have also been a lot of changes from my end: a unified manifest.xml format across all systems, major improvements to SPC7110 emulation, enhancements to RTC emulation, MSU1 enhancements, icons in the file browser list, improvements to SNES coprocessor memory mapping, cleanups and improvements in the libraries used to build bsnes, etc. I've also included kaijuu (which allows launching game folders directly with bsnes) and purify (which allows opening images that are compressed, have copier headers, and have wrong extensions); both of which are fully GUI-based. This release only loads game folders, not files. Use purify to load ROM files in bsnes. Note that this will likely be the last release for a long time, and that I will probably rename the emulator for the next release, due to how many additional systems it now supports. --- bsnes/Makefile | 19 +- bsnes/data/bsnes.Manifest | 0 bsnes/data/bsnes.desktop | 0 bsnes/data/bsnes.ico | Bin bsnes/data/bsnes.png | Bin bsnes/data/cheats.xml | 748 +++++++++- bsnes/data/laevateinn.hpp | 0 bsnes/emulator/emulator.hpp | 2 +- bsnes/emulator/interface.hpp | 0 bsnes/fc/Makefile | 0 bsnes/fc/apu/apu.cpp | 0 bsnes/fc/apu/apu.hpp | 0 bsnes/fc/apu/dmc.cpp | 0 bsnes/fc/apu/dmc.hpp | 0 bsnes/fc/apu/envelope.cpp | 0 bsnes/fc/apu/envelope.hpp | 0 bsnes/fc/apu/noise.cpp | 0 bsnes/fc/apu/noise.hpp | 0 bsnes/fc/apu/pulse.cpp | 0 bsnes/fc/apu/pulse.hpp | 0 bsnes/fc/apu/serialization.cpp | 0 bsnes/fc/apu/sweep.cpp | 0 bsnes/fc/apu/sweep.hpp | 0 bsnes/fc/apu/triangle.cpp | 0 bsnes/fc/apu/triangle.hpp | 0 bsnes/fc/cartridge/board/bandai-fcg.cpp | 0 bsnes/fc/cartridge/board/board.cpp | 0 bsnes/fc/cartridge/board/board.hpp | 0 bsnes/fc/cartridge/board/konami-vrc1.cpp | 0 bsnes/fc/cartridge/board/konami-vrc2.cpp | 0 bsnes/fc/cartridge/board/konami-vrc3.cpp | 0 bsnes/fc/cartridge/board/konami-vrc4.cpp | 0 bsnes/fc/cartridge/board/konami-vrc6.cpp | 0 bsnes/fc/cartridge/board/konami-vrc7.cpp | 0 bsnes/fc/cartridge/board/nes-axrom.cpp | 0 bsnes/fc/cartridge/board/nes-bnrom.cpp | 0 bsnes/fc/cartridge/board/nes-cnrom.cpp | 0 bsnes/fc/cartridge/board/nes-exrom.cpp | 0 bsnes/fc/cartridge/board/nes-fxrom.cpp | 0 bsnes/fc/cartridge/board/nes-gxrom.cpp | 0 bsnes/fc/cartridge/board/nes-hkrom.cpp | 0 bsnes/fc/cartridge/board/nes-nrom.cpp | 0 bsnes/fc/cartridge/board/nes-pxrom.cpp | 0 bsnes/fc/cartridge/board/nes-sxrom.cpp | 0 bsnes/fc/cartridge/board/nes-txrom.cpp | 0 bsnes/fc/cartridge/board/nes-uxrom.cpp | 0 bsnes/fc/cartridge/board/sunsoft-5b.cpp | 0 bsnes/fc/cartridge/cartridge.cpp | 0 bsnes/fc/cartridge/cartridge.hpp | 0 bsnes/fc/cartridge/chip/chip.cpp | 0 bsnes/fc/cartridge/chip/chip.hpp | 0 bsnes/fc/cartridge/chip/mmc1.cpp | 0 bsnes/fc/cartridge/chip/mmc3.cpp | 0 bsnes/fc/cartridge/chip/mmc5.cpp | 0 bsnes/fc/cartridge/chip/mmc6.cpp | 0 bsnes/fc/cartridge/chip/vrc1.cpp | 0 bsnes/fc/cartridge/chip/vrc2.cpp | 0 bsnes/fc/cartridge/chip/vrc3.cpp | 0 bsnes/fc/cartridge/chip/vrc4.cpp | 0 bsnes/fc/cartridge/chip/vrc6.cpp | 0 bsnes/fc/cartridge/chip/vrc7.cpp | 0 bsnes/fc/cheat/cheat.cpp | 0 bsnes/fc/cheat/cheat.hpp | 0 bsnes/fc/cpu/cpu.cpp | 0 bsnes/fc/cpu/cpu.hpp | 0 bsnes/fc/cpu/serialization.cpp | 0 bsnes/fc/cpu/timing.cpp | 0 bsnes/fc/fc.hpp | 0 bsnes/fc/input/input.cpp | 0 bsnes/fc/input/input.hpp | 0 bsnes/fc/input/serialization.cpp | 0 bsnes/fc/interface/interface.cpp | 0 bsnes/fc/interface/interface.hpp | 0 bsnes/fc/memory/memory.cpp | 0 bsnes/fc/memory/memory.hpp | 0 bsnes/fc/ppu/ppu.cpp | 0 bsnes/fc/ppu/ppu.hpp | 0 bsnes/fc/ppu/serialization.cpp | 0 bsnes/fc/scheduler/scheduler.cpp | 0 bsnes/fc/scheduler/scheduler.hpp | 0 bsnes/fc/system/serialization.cpp | 0 bsnes/fc/system/system.cpp | 0 bsnes/fc/system/system.hpp | 0 bsnes/fc/video/video.cpp | 0 bsnes/fc/video/video.hpp | 0 bsnes/gb/Makefile | 0 bsnes/gb/apu/apu.cpp | 0 bsnes/gb/apu/apu.hpp | 0 bsnes/gb/apu/master/master.cpp | 0 bsnes/gb/apu/master/master.hpp | 0 bsnes/gb/apu/noise/noise.cpp | 0 bsnes/gb/apu/noise/noise.hpp | 0 bsnes/gb/apu/serialization.cpp | 0 bsnes/gb/apu/square1/square1.cpp | 0 bsnes/gb/apu/square1/square1.hpp | 0 bsnes/gb/apu/square2/square2.cpp | 0 bsnes/gb/apu/square2/square2.hpp | 0 bsnes/gb/apu/wave/wave.cpp | 0 bsnes/gb/apu/wave/wave.hpp | 0 bsnes/gb/cartridge/cartridge.cpp | 0 bsnes/gb/cartridge/cartridge.hpp | 0 bsnes/gb/cartridge/huc1/huc1.cpp | 0 bsnes/gb/cartridge/huc1/huc1.hpp | 0 bsnes/gb/cartridge/huc3/huc3.cpp | 0 bsnes/gb/cartridge/huc3/huc3.hpp | 0 bsnes/gb/cartridge/mbc0/mbc0.cpp | 0 bsnes/gb/cartridge/mbc0/mbc0.hpp | 0 bsnes/gb/cartridge/mbc1/mbc1.cpp | 0 bsnes/gb/cartridge/mbc1/mbc1.hpp | 0 bsnes/gb/cartridge/mbc2/mbc2.cpp | 0 bsnes/gb/cartridge/mbc2/mbc2.hpp | 0 bsnes/gb/cartridge/mbc3/mbc3.cpp | 0 bsnes/gb/cartridge/mbc3/mbc3.hpp | 0 bsnes/gb/cartridge/mbc5/mbc5.cpp | 0 bsnes/gb/cartridge/mbc5/mbc5.hpp | 0 bsnes/gb/cartridge/mmm01/mmm01.cpp | 0 bsnes/gb/cartridge/mmm01/mmm01.hpp | 0 bsnes/gb/cartridge/serialization.cpp | 0 bsnes/gb/cheat/cheat.cpp | 0 bsnes/gb/cheat/cheat.hpp | 0 bsnes/gb/cpu/cpu.cpp | 0 bsnes/gb/cpu/cpu.hpp | 0 bsnes/gb/cpu/memory.cpp | 0 bsnes/gb/cpu/mmio.cpp | 0 bsnes/gb/cpu/serialization.cpp | 0 bsnes/gb/cpu/timing.cpp | 0 bsnes/gb/gb.hpp | 0 bsnes/gb/interface/interface.cpp | 0 bsnes/gb/interface/interface.hpp | 0 bsnes/gb/memory/memory.cpp | 0 bsnes/gb/memory/memory.hpp | 0 bsnes/gb/ppu/cgb.cpp | 0 bsnes/gb/ppu/dmg.cpp | 0 bsnes/gb/ppu/mmio.cpp | 0 bsnes/gb/ppu/ppu.cpp | 0 bsnes/gb/ppu/ppu.hpp | 0 bsnes/gb/ppu/serialization.cpp | 0 bsnes/gb/scheduler/scheduler.cpp | 0 bsnes/gb/scheduler/scheduler.hpp | 0 bsnes/gb/system/serialization.cpp | 0 bsnes/gb/system/system.cpp | 0 bsnes/gb/system/system.hpp | 0 bsnes/gb/video/video.cpp | 0 bsnes/gb/video/video.hpp | 0 bsnes/gba/Makefile | 0 bsnes/gba/apu/apu.cpp | 0 bsnes/gba/apu/apu.hpp | 0 bsnes/gba/apu/fifo.cpp | 0 bsnes/gba/apu/mmio.cpp | 0 bsnes/gba/apu/noise.cpp | 0 bsnes/gba/apu/registers.cpp | 0 bsnes/gba/apu/registers.hpp | 0 bsnes/gba/apu/sequencer.cpp | 0 bsnes/gba/apu/serialization.cpp | 0 bsnes/gba/apu/square.cpp | 0 bsnes/gba/apu/square1.cpp | 0 bsnes/gba/apu/square2.cpp | 0 bsnes/gba/apu/wave.cpp | 0 bsnes/gba/cartridge/cartridge.cpp | 0 bsnes/gba/cartridge/cartridge.hpp | 0 bsnes/gba/cartridge/eeprom.cpp | 0 bsnes/gba/cartridge/flashrom.cpp | 0 bsnes/gba/cartridge/memory.hpp | 0 bsnes/gba/cartridge/serialization.cpp | 0 bsnes/gba/cpu/cpu.cpp | 0 bsnes/gba/cpu/cpu.hpp | 0 bsnes/gba/cpu/dma.cpp | 0 bsnes/gba/cpu/memory.cpp | 0 bsnes/gba/cpu/mmio.cpp | 0 bsnes/gba/cpu/registers.cpp | 0 bsnes/gba/cpu/registers.hpp | 0 bsnes/gba/cpu/serialization.cpp | 0 bsnes/gba/cpu/state.hpp | 0 bsnes/gba/cpu/timer.cpp | 0 bsnes/gba/gba.hpp | 0 bsnes/gba/interface/interface.cpp | 0 bsnes/gba/interface/interface.hpp | 0 bsnes/gba/memory/memory.cpp | 0 bsnes/gba/memory/memory.hpp | 0 bsnes/gba/memory/mmio.cpp | 0 bsnes/gba/memory/serialization.cpp | 0 bsnes/gba/ppu/background.cpp | 0 bsnes/gba/ppu/memory.cpp | 0 bsnes/gba/ppu/mmio.cpp | 0 bsnes/gba/ppu/mosaic.cpp | 0 bsnes/gba/ppu/object.cpp | 0 bsnes/gba/ppu/ppu.cpp | 0 bsnes/gba/ppu/ppu.hpp | 0 bsnes/gba/ppu/registers.cpp | 0 bsnes/gba/ppu/registers.hpp | 0 bsnes/gba/ppu/screen.cpp | 0 bsnes/gba/ppu/serialization.cpp | 0 bsnes/gba/ppu/state.hpp | 0 bsnes/gba/scheduler/scheduler.cpp | 0 bsnes/gba/scheduler/scheduler.hpp | 0 bsnes/gba/system/bios.cpp | 0 bsnes/gba/system/serialization.cpp | 0 bsnes/gba/system/system.cpp | 0 bsnes/gba/system/system.hpp | 0 bsnes/gba/video/video.cpp | 0 bsnes/gba/video/video.hpp | 0 bsnes/libco/amd64.c | 0 bsnes/libco/fiber.c | 0 bsnes/libco/libco.c | 0 bsnes/libco/libco.h | 0 bsnes/libco/ppc.c | 0 bsnes/libco/sjlj.c | 0 bsnes/libco/ucontext.c | 0 bsnes/libco/x86.c | 0 bsnes/nall/Makefile | 0 bsnes/nall/algorithm.hpp | 0 bsnes/nall/any.hpp | 0 bsnes/nall/atoi.hpp | 0 bsnes/nall/base64.hpp | 0 bsnes/nall/bit.hpp | 0 bsnes/nall/bmp.hpp | 0 bsnes/nall/bps/delta.hpp | 0 bsnes/nall/bps/linear.hpp | 0 bsnes/nall/bps/metadata.hpp | 0 bsnes/nall/bps/patch.hpp | 0 bsnes/nall/compositor.hpp | 0 bsnes/nall/config.hpp | 0 bsnes/nall/crc32.hpp | 0 bsnes/nall/directory.hpp | 0 bsnes/nall/dl.hpp | 0 bsnes/nall/dsp.hpp | 0 bsnes/nall/dsp/buffer.hpp | 0 bsnes/nall/dsp/core.hpp | 0 bsnes/nall/dsp/resample/average.hpp | 0 bsnes/nall/dsp/resample/cosine.hpp | 0 bsnes/nall/dsp/resample/cubic.hpp | 0 bsnes/nall/dsp/resample/hermite.hpp | 0 bsnes/nall/dsp/resample/lib/sinc.hpp | 0 bsnes/nall/dsp/resample/linear.hpp | 0 bsnes/nall/dsp/resample/nearest.hpp | 0 bsnes/nall/dsp/resample/sinc.hpp | 0 bsnes/nall/dsp/settings.hpp | 0 bsnes/nall/emulation/famicom.hpp | 0 bsnes/nall/emulation/game-boy-advance.hpp | 0 bsnes/nall/emulation/game-boy.hpp | 0 bsnes/nall/emulation/satellaview.hpp | 0 bsnes/nall/emulation/sufami-turbo.hpp | 0 bsnes/nall/emulation/super-famicom-usart.hpp | 0 bsnes/nall/emulation/super-famicom.hpp | 3 + bsnes/nall/endian.hpp | 0 bsnes/nall/file.hpp | 0 bsnes/nall/filemap.hpp | 0 bsnes/nall/function.hpp | 0 bsnes/nall/gzip.hpp | 0 bsnes/nall/http.hpp | 0 bsnes/nall/image.hpp | 0 bsnes/nall/inflate.hpp | 0 bsnes/nall/input.hpp | 0 bsnes/nall/interpolation.hpp | 0 bsnes/nall/intrinsics.hpp | 0 bsnes/nall/invoke.hpp | 0 bsnes/nall/ips.hpp | 0 bsnes/nall/lzss.hpp | 0 bsnes/nall/map.hpp | 0 bsnes/nall/mosaic.hpp | 0 bsnes/nall/mosaic/bitstream.hpp | 0 bsnes/nall/mosaic/context.hpp | 0 bsnes/nall/mosaic/parser.hpp | 0 bsnes/nall/nall.hpp | 0 bsnes/nall/platform.hpp | 0 bsnes/nall/png.hpp | 0 bsnes/nall/priority-queue.hpp | 0 bsnes/nall/property.hpp | 0 bsnes/nall/public-cast.hpp | 0 bsnes/nall/random.hpp | 0 bsnes/nall/serial.hpp | 0 bsnes/nall/serializer.hpp | 0 bsnes/nall/set.hpp | 0 bsnes/nall/sha256.hpp | 0 bsnes/nall/sort.hpp | 0 bsnes/nall/stdint.hpp | 0 bsnes/nall/stream.hpp | 0 bsnes/nall/stream/auto.hpp | 0 bsnes/nall/stream/file.hpp | 0 bsnes/nall/stream/gzip.hpp | 0 bsnes/nall/stream/http.hpp | 0 bsnes/nall/stream/memory.hpp | 0 bsnes/nall/stream/mmap.hpp | 0 bsnes/nall/stream/stream.hpp | 0 bsnes/nall/stream/vector.hpp | 0 bsnes/nall/stream/zip.hpp | 0 bsnes/nall/string.hpp | 0 bsnes/nall/string/base.hpp | 0 bsnes/nall/string/bml.hpp | 0 bsnes/nall/string/bsv.hpp | 0 bsnes/nall/string/cast.hpp | 0 bsnes/nall/string/compare.hpp | 0 bsnes/nall/string/convert.hpp | 0 bsnes/nall/string/core.hpp | 0 bsnes/nall/string/cstring.hpp | 0 bsnes/nall/string/filename.hpp | 0 bsnes/nall/string/math-fixed-point.hpp | 0 bsnes/nall/string/math-floating-point.hpp | 0 bsnes/nall/string/platform.hpp | 0 bsnes/nall/string/replace.hpp | 0 bsnes/nall/string/split.hpp | 0 bsnes/nall/string/static.hpp | 0 bsnes/nall/string/strm.hpp | 0 bsnes/nall/string/strpos.hpp | 0 bsnes/nall/string/trim.hpp | 0 bsnes/nall/string/utf8.hpp | 0 bsnes/nall/string/utility.hpp | 0 bsnes/nall/string/variadic.hpp | 0 bsnes/nall/string/wildcard.hpp | 0 bsnes/nall/string/wrapper.hpp | 0 bsnes/nall/string/xml-legacy.hpp | 0 bsnes/nall/string/xml.hpp | 0 bsnes/nall/traits.hpp | 0 bsnes/nall/udl.hpp | 0 bsnes/nall/ups.hpp | 0 bsnes/nall/utility.hpp | 0 bsnes/nall/varint.hpp | 0 bsnes/nall/vector.hpp | 0 bsnes/nall/windows/detour.hpp | 0 bsnes/nall/windows/guid.hpp | 0 bsnes/nall/windows/launcher.hpp | 0 bsnes/nall/windows/registry.hpp | 0 bsnes/nall/windows/utf8.hpp | 0 bsnes/nall/xorg/guard.hpp | 0 bsnes/nall/xorg/xorg.hpp | 0 bsnes/nall/zip.hpp | 0 bsnes/nds/Makefile | 16 + bsnes/nds/apu/apu.cpp | 403 +++++ bsnes/nds/apu/apu.hpp | 100 ++ bsnes/nds/cpu/arm.cpp | 230 +++ bsnes/nds/cpu/arm7tdmi.cpp | 565 +++++++ bsnes/nds/cpu/arm946es.cpp | 697 +++++++++ bsnes/nds/cpu/bit.hpp | 66 + bsnes/nds/cpu/core.cpp | 214 +++ bsnes/nds/cpu/core.hpp | 135 ++ bsnes/nds/cpu/cpu.cpp | 337 +++++ bsnes/nds/cpu/cpu.hpp | 288 ++++ bsnes/nds/cpu/disasm.cpp | 411 +++++ bsnes/nds/cpu/dma.cpp | 131 ++ bsnes/nds/cpu/math.cpp | 115 ++ bsnes/nds/cpu/message.cpp | 98 ++ bsnes/nds/cpu/slot.cpp | 131 ++ bsnes/nds/cpu/thumb.cpp | 150 ++ bsnes/nds/cpu/timer.cpp | 78 + bsnes/nds/gpu/commands.cpp | 527 +++++++ bsnes/nds/gpu/commands.hpp | 41 + bsnes/nds/gpu/geometry.cpp | 316 ++++ bsnes/nds/gpu/geometry.hpp | 83 ++ bsnes/nds/gpu/gpu.cpp | 497 ++++++ bsnes/nds/gpu/gpu.hpp | 77 + bsnes/nds/gpu/math.cpp | 143 ++ bsnes/nds/gpu/math.hpp | 53 + bsnes/nds/gpu/render.cpp | 578 +++++++ bsnes/nds/gpu/render.hpp | 163 ++ bsnes/nds/gpu/textures.cpp | 304 ++++ bsnes/nds/interface/interface.cpp | 410 +++++ bsnes/nds/interface/interface.hpp | 91 ++ bsnes/nds/memory/eeprom.cpp | 96 ++ bsnes/nds/memory/eeprom.hpp | 17 + bsnes/nds/memory/flash.cpp | 137 ++ bsnes/nds/memory/flash.hpp | 20 + bsnes/nds/memory/fram.cpp | 64 + bsnes/nds/memory/fram.hpp | 16 + bsnes/nds/memory/memory.cpp | 127 ++ bsnes/nds/memory/memory.hpp | 76 + bsnes/nds/nds.hpp | 29 + bsnes/nds/ppu/bg.cpp | 251 ++++ bsnes/nds/ppu/obj.cpp | 159 ++ bsnes/nds/ppu/ppu.cpp | 414 +++++ bsnes/nds/ppu/ppu.hpp | 148 ++ bsnes/nds/slot1/slot1.cpp | 244 +++ bsnes/nds/slot1/slot1.hpp | 113 ++ bsnes/nds/slot2/slot2.cpp | 0 bsnes/nds/slot2/slot2.hpp | 0 bsnes/nds/system/clock.cpp | 239 +++ bsnes/nds/system/eventqueue.hpp | 120 ++ bsnes/nds/system/powermgr.cpp | 14 + bsnes/nds/system/system.cpp | 537 +++++++ bsnes/nds/system/system.hpp | 231 +++ bsnes/nds/system/touchscreen.cpp | 112 ++ bsnes/nds/video/video.cpp | 180 +++ bsnes/nds/video/video.hpp | 44 + bsnes/nds/wifi/wifi.cpp | 488 ++++++ bsnes/nds/wifi/wifi.hpp | 153 ++ bsnes/phoenix/Makefile | 0 bsnes/phoenix/core/core.cpp | 0 bsnes/phoenix/core/core.hpp | 0 bsnes/phoenix/core/keyboard.hpp | 0 bsnes/phoenix/core/layout/fixed-layout.cpp | 0 bsnes/phoenix/core/layout/fixed-layout.hpp | 0 .../phoenix/core/layout/horizontal-layout.cpp | 0 .../phoenix/core/layout/horizontal-layout.hpp | 0 bsnes/phoenix/core/layout/vertical-layout.cpp | 0 bsnes/phoenix/core/layout/vertical-layout.hpp | 0 bsnes/phoenix/core/state.hpp | 0 bsnes/phoenix/gtk/action/action.cpp | 0 bsnes/phoenix/gtk/action/check-item.cpp | 0 bsnes/phoenix/gtk/action/item.cpp | 0 bsnes/phoenix/gtk/action/menu.cpp | 0 bsnes/phoenix/gtk/action/radio-item.cpp | 0 bsnes/phoenix/gtk/action/separator.cpp | 0 bsnes/phoenix/gtk/desktop.cpp | 0 bsnes/phoenix/gtk/dialog-window.cpp | 0 bsnes/phoenix/gtk/font.cpp | 0 bsnes/phoenix/gtk/keyboard.cpp | 0 bsnes/phoenix/gtk/message-window.cpp | 0 bsnes/phoenix/gtk/mouse.cpp | 0 bsnes/phoenix/gtk/platform.cpp | 0 bsnes/phoenix/gtk/platform.hpp | 0 bsnes/phoenix/gtk/settings.cpp | 0 bsnes/phoenix/gtk/timer.cpp | 0 bsnes/phoenix/gtk/utility.cpp | 0 bsnes/phoenix/gtk/widget/button.cpp | 0 bsnes/phoenix/gtk/widget/canvas.cpp | 0 bsnes/phoenix/gtk/widget/check-box.cpp | 0 bsnes/phoenix/gtk/widget/combo-box.cpp | 0 bsnes/phoenix/gtk/widget/hex-edit.cpp | 0 .../gtk/widget/horizontal-scroll-bar.cpp | 0 .../phoenix/gtk/widget/horizontal-slider.cpp | 0 bsnes/phoenix/gtk/widget/label.cpp | 0 bsnes/phoenix/gtk/widget/line-edit.cpp | 0 bsnes/phoenix/gtk/widget/list-view.cpp | 0 bsnes/phoenix/gtk/widget/progress-bar.cpp | 0 bsnes/phoenix/gtk/widget/radio-box.cpp | 0 bsnes/phoenix/gtk/widget/text-edit.cpp | 0 .../gtk/widget/vertical-scroll-bar.cpp | 0 bsnes/phoenix/gtk/widget/vertical-slider.cpp | 0 bsnes/phoenix/gtk/widget/viewport.cpp | 0 bsnes/phoenix/gtk/widget/widget.cpp | 0 bsnes/phoenix/gtk/window.cpp | 0 bsnes/phoenix/phoenix.cpp | 0 bsnes/phoenix/phoenix.hpp | 0 bsnes/phoenix/qt/action/action.cpp | 0 bsnes/phoenix/qt/action/check-item.cpp | 0 bsnes/phoenix/qt/action/item.cpp | 0 bsnes/phoenix/qt/action/menu.cpp | 0 bsnes/phoenix/qt/action/radio-item.cpp | 0 bsnes/phoenix/qt/action/separator.cpp | 0 bsnes/phoenix/qt/desktop.cpp | 0 bsnes/phoenix/qt/dialog-window.cpp | 0 bsnes/phoenix/qt/font.cpp | 0 bsnes/phoenix/qt/keyboard.cpp | 0 bsnes/phoenix/qt/message-window.cpp | 0 bsnes/phoenix/qt/mouse.cpp | 0 bsnes/phoenix/qt/platform.cpp | 0 bsnes/phoenix/qt/platform.moc | 0 bsnes/phoenix/qt/platform.moc.hpp | 0 bsnes/phoenix/qt/settings.cpp | 0 bsnes/phoenix/qt/timer.cpp | 0 bsnes/phoenix/qt/utility.cpp | 0 bsnes/phoenix/qt/widget/button.cpp | 0 bsnes/phoenix/qt/widget/canvas.cpp | 0 bsnes/phoenix/qt/widget/check-box.cpp | 0 bsnes/phoenix/qt/widget/combo-box.cpp | 0 bsnes/phoenix/qt/widget/hex-edit.cpp | 0 .../qt/widget/horizontal-scroll-bar.cpp | 0 bsnes/phoenix/qt/widget/horizontal-slider.cpp | 0 bsnes/phoenix/qt/widget/label.cpp | 0 bsnes/phoenix/qt/widget/line-edit.cpp | 0 bsnes/phoenix/qt/widget/list-view.cpp | 0 bsnes/phoenix/qt/widget/progress-bar.cpp | 0 bsnes/phoenix/qt/widget/radio-box.cpp | 0 bsnes/phoenix/qt/widget/text-edit.cpp | 0 .../phoenix/qt/widget/vertical-scroll-bar.cpp | 0 bsnes/phoenix/qt/widget/vertical-slider.cpp | 0 bsnes/phoenix/qt/widget/viewport.cpp | 0 bsnes/phoenix/qt/widget/widget.cpp | 0 bsnes/phoenix/qt/window.cpp | 0 bsnes/phoenix/reference/action/action.cpp | 0 bsnes/phoenix/reference/action/check-item.cpp | 0 bsnes/phoenix/reference/action/item.cpp | 0 bsnes/phoenix/reference/action/menu.cpp | 0 bsnes/phoenix/reference/action/radio-item.cpp | 0 bsnes/phoenix/reference/action/separator.cpp | 0 bsnes/phoenix/reference/desktop.cpp | 0 bsnes/phoenix/reference/dialog-window.cpp | 0 bsnes/phoenix/reference/font.cpp | 0 bsnes/phoenix/reference/keyboard.cpp | 0 bsnes/phoenix/reference/message-window.cpp | 0 bsnes/phoenix/reference/mouse.cpp | 0 bsnes/phoenix/reference/platform.cpp | 0 bsnes/phoenix/reference/platform.hpp | 0 bsnes/phoenix/reference/timer.cpp | 0 bsnes/phoenix/reference/widget/button.cpp | 0 bsnes/phoenix/reference/widget/canvas.cpp | 0 bsnes/phoenix/reference/widget/check-box.cpp | 0 bsnes/phoenix/reference/widget/combo-box.cpp | 0 bsnes/phoenix/reference/widget/hex-edit.cpp | 0 .../widget/horizontal-scroll-bar.cpp | 0 .../reference/widget/horizontal-slider.cpp | 0 bsnes/phoenix/reference/widget/label.cpp | 0 bsnes/phoenix/reference/widget/line-edit.cpp | 0 bsnes/phoenix/reference/widget/list-view.cpp | 0 .../phoenix/reference/widget/progress-bar.cpp | 0 bsnes/phoenix/reference/widget/radio-box.cpp | 0 bsnes/phoenix/reference/widget/text-edit.cpp | 0 .../reference/widget/vertical-scroll-bar.cpp | 0 .../reference/widget/vertical-slider.cpp | 0 bsnes/phoenix/reference/widget/viewport.cpp | 0 bsnes/phoenix/reference/widget/widget.cpp | 0 bsnes/phoenix/reference/window.cpp | 0 bsnes/phoenix/sync.sh | 0 bsnes/phoenix/windows/action/action.cpp | 0 bsnes/phoenix/windows/action/check-item.cpp | 0 bsnes/phoenix/windows/action/item.cpp | 0 bsnes/phoenix/windows/action/menu.cpp | 0 bsnes/phoenix/windows/action/radio-item.cpp | 0 bsnes/phoenix/windows/action/separator.cpp | 0 bsnes/phoenix/windows/desktop.cpp | 0 bsnes/phoenix/windows/dialog-window.cpp | 0 bsnes/phoenix/windows/font.cpp | 0 bsnes/phoenix/windows/keyboard.cpp | 0 bsnes/phoenix/windows/message-window.cpp | 0 bsnes/phoenix/windows/mouse.cpp | 0 bsnes/phoenix/windows/object.cpp | 0 bsnes/phoenix/windows/phoenix.Manifest | 0 bsnes/phoenix/windows/phoenix.rc | 0 bsnes/phoenix/windows/platform.cpp | 0 bsnes/phoenix/windows/platform.hpp | 0 bsnes/phoenix/windows/settings.cpp | 0 bsnes/phoenix/windows/timer.cpp | 0 bsnes/phoenix/windows/utility.cpp | 0 bsnes/phoenix/windows/widget/button.cpp | 0 bsnes/phoenix/windows/widget/canvas.cpp | 0 bsnes/phoenix/windows/widget/check-box.cpp | 0 bsnes/phoenix/windows/widget/combo-box.cpp | 0 bsnes/phoenix/windows/widget/hex-edit.cpp | 0 .../windows/widget/horizontal-scroll-bar.cpp | 0 .../windows/widget/horizontal-slider.cpp | 0 bsnes/phoenix/windows/widget/label.cpp | 0 bsnes/phoenix/windows/widget/line-edit.cpp | 0 bsnes/phoenix/windows/widget/list-view.cpp | 0 bsnes/phoenix/windows/widget/progress-bar.cpp | 0 bsnes/phoenix/windows/widget/radio-box.cpp | 0 bsnes/phoenix/windows/widget/text-edit.cpp | 0 .../windows/widget/vertical-scroll-bar.cpp | 0 .../windows/widget/vertical-slider.cpp | 0 bsnes/phoenix/windows/widget/viewport.cpp | 0 bsnes/phoenix/windows/widget/widget.cpp | 0 bsnes/phoenix/windows/window.cpp | 0 bsnes/processor/Makefile | 0 bsnes/processor/arm/algorithms.cpp | 0 bsnes/processor/arm/arm.cpp | 0 bsnes/processor/arm/arm.hpp | 0 bsnes/processor/arm/disassembler.cpp | 0 bsnes/processor/arm/disassembler.hpp | 0 bsnes/processor/arm/instructions-arm.cpp | 0 bsnes/processor/arm/instructions-arm.hpp | 0 bsnes/processor/arm/instructions-thumb.cpp | 0 bsnes/processor/arm/instructions-thumb.hpp | 0 bsnes/processor/arm/registers.cpp | 0 bsnes/processor/arm/registers.hpp | 0 bsnes/processor/arm/serialization.cpp | 0 bsnes/processor/gsu/gsu.cpp | 0 bsnes/processor/gsu/gsu.hpp | 0 bsnes/processor/gsu/instructions.cpp | 0 bsnes/processor/gsu/registers.hpp | 0 bsnes/processor/gsu/serialization.cpp | 0 bsnes/processor/gsu/table.cpp | 0 bsnes/processor/hg51b/hg51b.cpp | 0 bsnes/processor/hg51b/hg51b.hpp | 0 bsnes/processor/hg51b/instructions.cpp | 0 bsnes/processor/hg51b/registers.cpp | 0 bsnes/processor/hg51b/registers.hpp | 0 bsnes/processor/hg51b/serialization.cpp | 0 bsnes/processor/lr35902/disassembler.cpp | 0 bsnes/processor/lr35902/instructions.cpp | 0 bsnes/processor/lr35902/lr35902.cpp | 0 bsnes/processor/lr35902/lr35902.hpp | 0 bsnes/processor/lr35902/registers.hpp | 0 bsnes/processor/lr35902/serialization.cpp | 0 bsnes/processor/processor.hpp | 0 bsnes/processor/r6502/disassembler.cpp | 0 bsnes/processor/r6502/instructions.cpp | 0 bsnes/processor/r6502/memory.cpp | 0 bsnes/processor/r6502/r6502.cpp | 0 bsnes/processor/r6502/r6502.hpp | 0 bsnes/processor/r6502/registers.hpp | 0 bsnes/processor/r6502/serialization.cpp | 0 bsnes/processor/r65816/algorithms.cpp | 0 bsnes/processor/r65816/disassembler.cpp | 0 bsnes/processor/r65816/disassembler.hpp | 0 bsnes/processor/r65816/memory.hpp | 0 bsnes/processor/r65816/opcode_misc.cpp | 0 bsnes/processor/r65816/opcode_pc.cpp | 0 bsnes/processor/r65816/opcode_read.cpp | 0 bsnes/processor/r65816/opcode_rmw.cpp | 0 bsnes/processor/r65816/opcode_write.cpp | 0 bsnes/processor/r65816/r65816.cpp | 0 bsnes/processor/r65816/r65816.hpp | 0 bsnes/processor/r65816/registers.hpp | 0 bsnes/processor/r65816/serialization.cpp | 0 bsnes/processor/r65816/table.cpp | 0 bsnes/processor/spc700/algorithms.cpp | 0 bsnes/processor/spc700/disassembler.cpp | 0 bsnes/processor/spc700/instructions.cpp | 0 bsnes/processor/spc700/memory.hpp | 0 bsnes/processor/spc700/registers.hpp | 0 bsnes/processor/spc700/serialization.cpp | 0 bsnes/processor/spc700/spc700.cpp | 0 bsnes/processor/spc700/spc700.hpp | 0 bsnes/processor/upd96050/disassembler.cpp | 0 bsnes/processor/upd96050/instructions.cpp | 0 bsnes/processor/upd96050/memory.cpp | 0 bsnes/processor/upd96050/registers.hpp | 0 bsnes/processor/upd96050/serialization.cpp | 0 bsnes/processor/upd96050/upd96050.cpp | 0 bsnes/processor/upd96050/upd96050.hpp | 0 .../profile/BS-X Satellaview.sfc/manifest.xml | 0 bsnes/profile/Famicom.sys/manifest.xml | 0 .../profile/Game Boy Advance.sys/manifest.xml | 0 bsnes/profile/Game Boy Color.sys/boot.rom | Bin bsnes/profile/Game Boy Color.sys/manifest.xml | 0 bsnes/profile/Game Boy.sys/boot.rom | Bin bsnes/profile/Game Boy.sys/manifest.xml | 0 bsnes/profile/Nintendo DS.sys/manifest.xml | 31 + bsnes/profile/Sufami Turbo.sfc/manifest.xml | 0 bsnes/profile/Super Famicom.sys/manifest.xml | 0 bsnes/profile/Super Famicom.sys/spc700.rom | Bin bsnes/profile/Super Game Boy.sfc/boot.rom | Bin bsnes/profile/Super Game Boy.sfc/manifest.xml | 0 bsnes/ruby/Makefile | 0 bsnes/ruby/audio.hpp | 0 bsnes/ruby/audio/alsa.cpp | 0 bsnes/ruby/audio/ao.cpp | 0 bsnes/ruby/audio/directsound.cpp | 0 bsnes/ruby/audio/openal.cpp | 0 bsnes/ruby/audio/oss.cpp | 0 bsnes/ruby/audio/pulseaudio.cpp | 0 bsnes/ruby/audio/pulseaudiosimple.cpp | 0 bsnes/ruby/audio/xaudio2.cpp | 0 bsnes/ruby/audio/xaudio2.hpp | 0 bsnes/ruby/input.hpp | 0 bsnes/ruby/input/carbon.cpp | 0 bsnes/ruby/input/directinput.cpp | 0 bsnes/ruby/input/rawinput.cpp | 0 bsnes/ruby/input/sdl.cpp | 0 bsnes/ruby/input/x.cpp | 0 bsnes/ruby/input/xlibkeys.hpp | 0 bsnes/ruby/ruby.cpp | 0 bsnes/ruby/ruby.hpp | 0 bsnes/ruby/ruby_impl.cpp | 0 bsnes/ruby/video.hpp | 0 bsnes/ruby/video/direct3d.cpp | 0 bsnes/ruby/video/directdraw.cpp | 0 bsnes/ruby/video/gdi.cpp | 0 bsnes/ruby/video/glx.cpp | 0 bsnes/ruby/video/opengl.hpp | 0 bsnes/ruby/video/qtopengl.cpp | 0 bsnes/ruby/video/qtraster.cpp | 0 bsnes/ruby/video/sdl.cpp | 0 bsnes/ruby/video/wgl.cpp | 0 bsnes/ruby/video/xshm.cpp | 0 bsnes/ruby/video/xv.cpp | 0 bsnes/sfc/Makefile | 0 bsnes/sfc/alt/cpu/cpu.cpp | 0 bsnes/sfc/alt/cpu/cpu.hpp | 0 bsnes/sfc/alt/cpu/dma.cpp | 0 bsnes/sfc/alt/cpu/memory.cpp | 0 bsnes/sfc/alt/cpu/mmio.cpp | 0 bsnes/sfc/alt/cpu/serialization.cpp | 0 bsnes/sfc/alt/cpu/timing.cpp | 0 bsnes/sfc/alt/dsp/SPC_DSP.cpp | 0 bsnes/sfc/alt/dsp/SPC_DSP.h | 0 bsnes/sfc/alt/dsp/blargg_common.h | 0 bsnes/sfc/alt/dsp/blargg_config.h | 0 bsnes/sfc/alt/dsp/blargg_endian.h | 0 bsnes/sfc/alt/dsp/blargg_source.h | 0 bsnes/sfc/alt/dsp/dsp.cpp | 0 bsnes/sfc/alt/dsp/dsp.hpp | 0 bsnes/sfc/alt/dsp/serialization.cpp | 0 .../alt/ppu-compatibility/memory/memory.cpp | 0 .../alt/ppu-compatibility/memory/memory.hpp | 0 bsnes/sfc/alt/ppu-compatibility/mmio/mmio.cpp | 0 bsnes/sfc/alt/ppu-compatibility/mmio/mmio.hpp | 0 bsnes/sfc/alt/ppu-compatibility/ppu.cpp | 0 bsnes/sfc/alt/ppu-compatibility/ppu.hpp | 0 .../alt/ppu-compatibility/render/addsub.cpp | 0 bsnes/sfc/alt/ppu-compatibility/render/bg.cpp | 0 .../alt/ppu-compatibility/render/cache.cpp | 0 .../sfc/alt/ppu-compatibility/render/line.cpp | 0 .../alt/ppu-compatibility/render/mode7.cpp | 0 .../sfc/alt/ppu-compatibility/render/oam.cpp | 0 .../alt/ppu-compatibility/render/render.cpp | 0 .../alt/ppu-compatibility/render/render.hpp | 0 .../alt/ppu-compatibility/render/windows.cpp | 0 .../alt/ppu-compatibility/serialization.cpp | 0 .../ppu-performance/background/background.cpp | 0 .../ppu-performance/background/background.hpp | 0 .../alt/ppu-performance/background/mode7.cpp | 0 bsnes/sfc/alt/ppu-performance/cache/cache.cpp | 0 bsnes/sfc/alt/ppu-performance/cache/cache.hpp | 0 bsnes/sfc/alt/ppu-performance/mmio/mmio.cpp | 0 bsnes/sfc/alt/ppu-performance/mmio/mmio.hpp | 0 bsnes/sfc/alt/ppu-performance/ppu.cpp | 0 bsnes/sfc/alt/ppu-performance/ppu.hpp | 0 .../sfc/alt/ppu-performance/screen/screen.cpp | 0 .../sfc/alt/ppu-performance/screen/screen.hpp | 0 .../sfc/alt/ppu-performance/serialization.cpp | 0 .../sfc/alt/ppu-performance/sprite/sprite.cpp | 0 .../sfc/alt/ppu-performance/sprite/sprite.hpp | 0 .../sfc/alt/ppu-performance/window/window.cpp | 0 .../sfc/alt/ppu-performance/window/window.hpp | 0 bsnes/sfc/alt/smp/algorithms.cpp | 0 bsnes/sfc/alt/smp/core.cpp | 0 bsnes/sfc/alt/smp/core/cc.sh | 0 bsnes/sfc/alt/smp/core/generate.cpp | 0 bsnes/sfc/alt/smp/core/op_misc.b | 0 bsnes/sfc/alt/smp/core/op_misc.cpp | 0 bsnes/sfc/alt/smp/core/op_mov.b | 0 bsnes/sfc/alt/smp/core/op_mov.cpp | 0 bsnes/sfc/alt/smp/core/op_pc.b | 0 bsnes/sfc/alt/smp/core/op_pc.cpp | 0 bsnes/sfc/alt/smp/core/op_read.b | 0 bsnes/sfc/alt/smp/core/op_read.cpp | 0 bsnes/sfc/alt/smp/core/op_rmw.b | 0 bsnes/sfc/alt/smp/core/op_rmw.cpp | 0 bsnes/sfc/alt/smp/core/opcycle_misc.cpp | 0 bsnes/sfc/alt/smp/core/opcycle_mov.cpp | 0 bsnes/sfc/alt/smp/core/opcycle_pc.cpp | 0 bsnes/sfc/alt/smp/core/opcycle_read.cpp | 0 bsnes/sfc/alt/smp/core/opcycle_rmw.cpp | 0 bsnes/sfc/alt/smp/disassembler.cpp | 0 bsnes/sfc/alt/smp/memory.cpp | 0 bsnes/sfc/alt/smp/smp.cpp | 0 bsnes/sfc/alt/smp/smp.hpp | 0 bsnes/sfc/alt/smp/timing.cpp | 0 bsnes/sfc/cartridge/cartridge.cpp | 0 bsnes/sfc/cartridge/cartridge.hpp | 0 bsnes/sfc/cartridge/markup.cpp | 0 bsnes/sfc/cartridge/serialization.cpp | 0 bsnes/sfc/cheat/cheat.cpp | 0 bsnes/sfc/cheat/cheat.hpp | 0 bsnes/sfc/chip/armdsp/armdsp.cpp | 0 bsnes/sfc/chip/armdsp/armdsp.hpp | 0 bsnes/sfc/chip/armdsp/memory.cpp | 0 bsnes/sfc/chip/armdsp/registers.hpp | 0 bsnes/sfc/chip/armdsp/serialization.cpp | 0 bsnes/sfc/chip/bsx/bsx.cpp | 0 bsnes/sfc/chip/bsx/bsx.hpp | 0 bsnes/sfc/chip/bsx/cartridge/cartridge.cpp | 0 bsnes/sfc/chip/bsx/cartridge/cartridge.hpp | 0 .../sfc/chip/bsx/cartridge/serialization.cpp | 0 bsnes/sfc/chip/bsx/flash/flash.cpp | 0 bsnes/sfc/chip/bsx/flash/flash.hpp | 0 .../sfc/chip/bsx/satellaview/satellaview.cpp | 0 .../sfc/chip/bsx/satellaview/satellaview.hpp | 0 bsnes/sfc/chip/chip.hpp | 0 bsnes/sfc/chip/epsonrtc/epsonrtc.cpp | 0 bsnes/sfc/chip/epsonrtc/epsonrtc.hpp | 0 bsnes/sfc/chip/epsonrtc/memory.cpp | 0 bsnes/sfc/chip/epsonrtc/serialization.cpp | 0 bsnes/sfc/chip/epsonrtc/time.cpp | 0 bsnes/sfc/chip/hitachidsp/hitachidsp.cpp | 0 bsnes/sfc/chip/hitachidsp/hitachidsp.hpp | 0 bsnes/sfc/chip/hitachidsp/memory.cpp | 0 bsnes/sfc/chip/hitachidsp/mmio.hpp | 0 bsnes/sfc/chip/hitachidsp/serialization.cpp | 0 bsnes/sfc/chip/icd2/icd2.cpp | 0 bsnes/sfc/chip/icd2/icd2.hpp | 0 bsnes/sfc/chip/icd2/interface/interface.cpp | 0 bsnes/sfc/chip/icd2/interface/interface.hpp | 0 bsnes/sfc/chip/icd2/mmio/mmio.cpp | 0 bsnes/sfc/chip/icd2/mmio/mmio.hpp | 0 bsnes/sfc/chip/icd2/serialization.cpp | 0 bsnes/sfc/chip/msu1/msu1.cpp | 0 bsnes/sfc/chip/msu1/msu1.hpp | 0 bsnes/sfc/chip/msu1/serialization.cpp | 0 bsnes/sfc/chip/necdsp/necdsp.cpp | 0 bsnes/sfc/chip/necdsp/necdsp.hpp | 0 bsnes/sfc/chip/necdsp/serialization.cpp | 0 bsnes/sfc/chip/nss/nss.cpp | 0 bsnes/sfc/chip/nss/nss.hpp | 0 bsnes/sfc/chip/obc1/obc1.cpp | 0 bsnes/sfc/chip/obc1/obc1.hpp | 0 bsnes/sfc/chip/obc1/serialization.cpp | 0 bsnes/sfc/chip/sa1/bus/bus.cpp | 0 bsnes/sfc/chip/sa1/bus/bus.hpp | 0 bsnes/sfc/chip/sa1/dma/dma.cpp | 0 bsnes/sfc/chip/sa1/dma/dma.hpp | 0 bsnes/sfc/chip/sa1/memory/memory.cpp | 0 bsnes/sfc/chip/sa1/memory/memory.hpp | 0 bsnes/sfc/chip/sa1/mmio/mmio.cpp | 0 bsnes/sfc/chip/sa1/mmio/mmio.hpp | 0 bsnes/sfc/chip/sa1/sa1.cpp | 0 bsnes/sfc/chip/sa1/sa1.hpp | 0 bsnes/sfc/chip/sa1/serialization.cpp | 0 bsnes/sfc/chip/sdd1/decomp.cpp | 0 bsnes/sfc/chip/sdd1/decomp.hpp | 0 bsnes/sfc/chip/sdd1/sdd1.cpp | 0 bsnes/sfc/chip/sdd1/sdd1.hpp | 0 bsnes/sfc/chip/sdd1/serialization.cpp | 0 bsnes/sfc/chip/sharprtc/memory.cpp | 0 bsnes/sfc/chip/sharprtc/serialization.cpp | 0 bsnes/sfc/chip/sharprtc/sharprtc.cpp | 0 bsnes/sfc/chip/sharprtc/sharprtc.hpp | 0 bsnes/sfc/chip/sharprtc/time.cpp | 0 bsnes/sfc/chip/spc7110/alu.cpp | 0 bsnes/sfc/chip/spc7110/data.cpp | 0 bsnes/sfc/chip/spc7110/dcu.cpp | 0 bsnes/sfc/chip/spc7110/decompressor.cpp | 0 bsnes/sfc/chip/spc7110/serialization.cpp | 0 bsnes/sfc/chip/spc7110/spc7110.cpp | 0 bsnes/sfc/chip/spc7110/spc7110.hpp | 0 bsnes/sfc/chip/sufamiturbo/serialization.cpp | 0 bsnes/sfc/chip/sufamiturbo/sufamiturbo.cpp | 0 bsnes/sfc/chip/sufamiturbo/sufamiturbo.hpp | 0 bsnes/sfc/chip/superfx/bus/bus.cpp | 0 bsnes/sfc/chip/superfx/bus/bus.hpp | 0 bsnes/sfc/chip/superfx/core/core.cpp | 0 bsnes/sfc/chip/superfx/core/core.hpp | 0 bsnes/sfc/chip/superfx/disasm/disasm.cpp | 0 bsnes/sfc/chip/superfx/disasm/disasm.hpp | 0 bsnes/sfc/chip/superfx/memory/memory.cpp | 0 bsnes/sfc/chip/superfx/memory/memory.hpp | 0 bsnes/sfc/chip/superfx/mmio/mmio.cpp | 0 bsnes/sfc/chip/superfx/mmio/mmio.hpp | 0 bsnes/sfc/chip/superfx/serialization.cpp | 0 bsnes/sfc/chip/superfx/superfx.cpp | 0 bsnes/sfc/chip/superfx/superfx.hpp | 0 bsnes/sfc/chip/superfx/timing/timing.cpp | 0 bsnes/sfc/chip/superfx/timing/timing.hpp | 0 bsnes/sfc/config/config.cpp | 0 bsnes/sfc/config/config.hpp | 0 bsnes/sfc/controller/controller.cpp | 0 bsnes/sfc/controller/controller.hpp | 0 bsnes/sfc/controller/gamepad/gamepad.cpp | 43 +- bsnes/sfc/controller/gamepad/gamepad.hpp | 4 + bsnes/sfc/controller/justifier/justifier.cpp | 0 bsnes/sfc/controller/justifier/justifier.hpp | 0 bsnes/sfc/controller/mouse/mouse.cpp | 84 +- bsnes/sfc/controller/mouse/mouse.hpp | 15 +- bsnes/sfc/controller/multitap/multitap.cpp | 0 bsnes/sfc/controller/multitap/multitap.hpp | 0 .../sfc/controller/superscope/superscope.cpp | 0 .../sfc/controller/superscope/superscope.hpp | 0 bsnes/sfc/controller/usart/usart.cpp | 0 bsnes/sfc/controller/usart/usart.hpp | 0 bsnes/sfc/cpu/cpu.cpp | 0 bsnes/sfc/cpu/cpu.hpp | 0 bsnes/sfc/cpu/dma/dma.cpp | 0 bsnes/sfc/cpu/dma/dma.hpp | 0 bsnes/sfc/cpu/memory/memory.cpp | 0 bsnes/sfc/cpu/memory/memory.hpp | 0 bsnes/sfc/cpu/mmio/mmio.cpp | 0 bsnes/sfc/cpu/mmio/mmio.hpp | 0 bsnes/sfc/cpu/serialization.cpp | 0 bsnes/sfc/cpu/timing/irq.cpp | 0 bsnes/sfc/cpu/timing/joypad.cpp | 0 bsnes/sfc/cpu/timing/timing.cpp | 0 bsnes/sfc/cpu/timing/timing.hpp | 0 bsnes/sfc/dsp/brr.cpp | 0 bsnes/sfc/dsp/counter.cpp | 0 bsnes/sfc/dsp/dsp.cpp | 0 bsnes/sfc/dsp/dsp.hpp | 0 bsnes/sfc/dsp/echo.cpp | 0 bsnes/sfc/dsp/envelope.cpp | 0 bsnes/sfc/dsp/gaussian.cpp | 0 bsnes/sfc/dsp/misc.cpp | 0 bsnes/sfc/dsp/moduloarray.hpp | 0 bsnes/sfc/dsp/serialization.cpp | 0 bsnes/sfc/dsp/voice.cpp | 0 bsnes/sfc/interface/interface.cpp | 2 +- bsnes/sfc/interface/interface.hpp | 0 bsnes/sfc/memory/memory-inline.hpp | 0 bsnes/sfc/memory/memory.cpp | 0 bsnes/sfc/memory/memory.hpp | 0 bsnes/sfc/ppu/background/background.cpp | 0 bsnes/sfc/ppu/background/background.hpp | 0 bsnes/sfc/ppu/background/mode7.cpp | 0 bsnes/sfc/ppu/counter/counter-inline.hpp | 0 bsnes/sfc/ppu/counter/counter.hpp | 0 bsnes/sfc/ppu/mmio/mmio.cpp | 0 bsnes/sfc/ppu/mmio/mmio.hpp | 0 bsnes/sfc/ppu/ppu.cpp | 0 bsnes/sfc/ppu/ppu.hpp | 0 bsnes/sfc/ppu/screen/screen.cpp | 0 bsnes/sfc/ppu/screen/screen.hpp | 0 bsnes/sfc/ppu/serialization.cpp | 0 bsnes/sfc/ppu/sprite/list.cpp | 0 bsnes/sfc/ppu/sprite/sprite.cpp | 0 bsnes/sfc/ppu/sprite/sprite.hpp | 0 bsnes/sfc/ppu/window/window.cpp | 0 bsnes/sfc/ppu/window/window.hpp | 0 bsnes/sfc/profile-accuracy.hpp | 0 bsnes/sfc/profile-compatibility.hpp | 0 bsnes/sfc/profile-performance.hpp | 0 bsnes/sfc/random/random.cpp | 0 bsnes/sfc/random/random.hpp | 0 bsnes/sfc/scheduler/scheduler.cpp | 0 bsnes/sfc/scheduler/scheduler.hpp | 0 bsnes/sfc/sfc.hpp | 0 bsnes/sfc/smp/memory.cpp | 0 bsnes/sfc/smp/serialization.cpp | 0 bsnes/sfc/smp/smp.cpp | 0 bsnes/sfc/smp/smp.hpp | 0 bsnes/sfc/smp/timing.cpp | 0 bsnes/sfc/system/audio.cpp | 0 bsnes/sfc/system/audio.hpp | 0 bsnes/sfc/system/input.cpp | 0 bsnes/sfc/system/input.hpp | 0 bsnes/sfc/system/serialization.cpp | 0 bsnes/sfc/system/system.cpp | 0 bsnes/sfc/system/system.hpp | 0 bsnes/sfc/system/video.cpp | 0 bsnes/sfc/system/video.hpp | 0 bsnes/target-ethos/Makefile | 6 +- bsnes/target-ethos/bootstrap.cpp | 2 + .../configuration/configuration.cpp | 0 .../configuration/configuration.hpp | 0 bsnes/target-ethos/ethos.cpp | 0 bsnes/target-ethos/ethos.hpp | 0 bsnes/target-ethos/general/browser.cpp | 0 bsnes/target-ethos/general/browser.hpp | 0 bsnes/target-ethos/general/dip-switches.cpp | 0 bsnes/target-ethos/general/dip-switches.hpp | 0 bsnes/target-ethos/general/general.cpp | 0 bsnes/target-ethos/general/general.hpp | 0 bsnes/target-ethos/general/presentation.cpp | 0 bsnes/target-ethos/general/presentation.hpp | 0 bsnes/target-ethos/input/hotkeys.cpp | 0 bsnes/target-ethos/input/input.cpp | 0 bsnes/target-ethos/input/input.hpp | 0 bsnes/target-ethos/interface/interface.cpp | 0 bsnes/target-ethos/interface/interface.hpp | 0 bsnes/target-ethos/resource.rc | 0 bsnes/target-ethos/resource/folder.png | Bin bsnes/target-ethos/resource/game.png | Bin bsnes/target-ethos/resource/home.png | Bin bsnes/target-ethos/resource/resource.cpp | 0 bsnes/target-ethos/resource/resource.hpp | 0 bsnes/target-ethos/resource/resource.xml | 0 bsnes/target-ethos/resource/up.png | Bin bsnes/target-ethos/settings/audio.cpp | 0 bsnes/target-ethos/settings/audio.hpp | 0 bsnes/target-ethos/settings/driver.cpp | 0 bsnes/target-ethos/settings/driver.hpp | 0 bsnes/target-ethos/settings/hotkey.cpp | 0 bsnes/target-ethos/settings/hotkey.hpp | 0 bsnes/target-ethos/settings/input.cpp | 0 bsnes/target-ethos/settings/input.hpp | 0 bsnes/target-ethos/settings/settings.cpp | 0 bsnes/target-ethos/settings/settings.hpp | 0 bsnes/target-ethos/settings/timing.cpp | 0 bsnes/target-ethos/settings/timing.hpp | 0 bsnes/target-ethos/settings/video.cpp | 0 bsnes/target-ethos/settings/video.hpp | 0 bsnes/target-ethos/tools/cheat-database.cpp | 0 bsnes/target-ethos/tools/cheat-database.hpp | 0 bsnes/target-ethos/tools/cheat-editor.cpp | 0 bsnes/target-ethos/tools/cheat-editor.hpp | 0 bsnes/target-ethos/tools/state-manager.cpp | 0 bsnes/target-ethos/tools/state-manager.hpp | 0 bsnes/target-ethos/tools/tools.cpp | 0 bsnes/target-ethos/tools/tools.hpp | 0 bsnes/target-ethos/utility/utility.cpp | 0 bsnes/target-ethos/utility/utility.hpp | 0 bsnes/target-ethos/window/window.cpp | 0 bsnes/target-ethos/window/window.hpp | 0 bsnes/target-laevateinn/Makefile | 0 bsnes/target-laevateinn/base.hpp | 0 .../breakpoint/breakpoint.cpp | 0 .../breakpoint/breakpoint.hpp | 0 bsnes/target-laevateinn/console/about.cpp | 0 bsnes/target-laevateinn/console/console.cpp | 0 bsnes/target-laevateinn/console/console.hpp | 0 bsnes/target-laevateinn/cpu/cpu.cpp | 0 bsnes/target-laevateinn/cpu/cpu.hpp | 0 bsnes/target-laevateinn/cpu/registers.cpp | 0 bsnes/target-laevateinn/debugger/debugger.cpp | 0 bsnes/target-laevateinn/debugger/debugger.hpp | 0 bsnes/target-laevateinn/debugger/hook.cpp | 0 bsnes/target-laevateinn/debugger/usage.cpp | 0 .../target-laevateinn/interface/interface.cpp | 0 .../target-laevateinn/interface/interface.hpp | 0 bsnes/target-laevateinn/main.cpp | 0 bsnes/target-laevateinn/memory/memory.cpp | 0 bsnes/target-laevateinn/memory/memory.hpp | 0 .../properties/properties.cpp | 0 .../properties/properties.hpp | 0 bsnes/target-laevateinn/resource.rc | 0 bsnes/target-laevateinn/settings/settings.cpp | 0 bsnes/target-laevateinn/settings/settings.hpp | 0 bsnes/target-laevateinn/smp/registers.cpp | 0 bsnes/target-laevateinn/smp/smp.cpp | 0 bsnes/target-laevateinn/smp/smp.hpp | 0 bsnes/target-laevateinn/tracer/tracer.cpp | 0 bsnes/target-laevateinn/tracer/tracer.hpp | 0 bsnes/target-laevateinn/video/video.cpp | 0 bsnes/target-laevateinn/video/video.hpp | 0 bsnes/target-laevateinn/vram/vram.cpp | 0 bsnes/target-laevateinn/vram/vram.hpp | 0 bsnes/target-laevateinn/window/window.cpp | 0 bsnes/target-laevateinn/window/window.hpp | 0 kaijuu/Makefile | 18 + kaijuu/cc32.bat | 8 + kaijuu/cc64.bat | 8 + kaijuu/extension.cpp | 175 +++ kaijuu/extension.hpp | 23 + kaijuu/factory.cpp | 40 + kaijuu/factory.hpp | 17 + kaijuu/guid.hpp | 11 + kaijuu/interface.cpp | 307 ++++ kaijuu/interface.hpp | 72 + kaijuu/kaijuu.Manifest | 21 + kaijuu/kaijuu.cpp | 50 + kaijuu/kaijuu.def | 5 + kaijuu/kaijuu.hpp | 25 + kaijuu/kaijuu.html | 200 +++ kaijuu/kaijuu.rc | 1 + {snesfilter => kaijuu}/nall/Makefile | 10 +- {snesfilter => kaijuu}/nall/algorithm.hpp | 0 {snesfilter => kaijuu}/nall/any.hpp | 17 +- {snesfilter => kaijuu}/nall/atoi.hpp | 15 + {snesfilter => kaijuu}/nall/base64.hpp | 0 kaijuu/nall/bit.hpp | 82 + {snesfilter => kaijuu}/nall/bmp.hpp | 0 {snesfilter => kaijuu}/nall/bps/delta.hpp | 0 {snesfilter => kaijuu}/nall/bps/linear.hpp | 0 {snesfilter => kaijuu}/nall/bps/metadata.hpp | 0 {snesfilter => kaijuu}/nall/bps/patch.hpp | 0 {snesfilter => kaijuu}/nall/compositor.hpp | 0 {snesfilter => kaijuu}/nall/config.hpp | 37 +- {snesfilter => kaijuu}/nall/crc32.hpp | 0 {snesfilter => kaijuu}/nall/directory.hpp | 46 +- {snesfilter => kaijuu}/nall/dl.hpp | 0 {snesfilter => kaijuu}/nall/dsp.hpp | 0 {snesfilter => kaijuu}/nall/dsp/buffer.hpp | 0 {snesfilter => kaijuu}/nall/dsp/core.hpp | 0 .../nall/dsp/resample/average.hpp | 0 .../nall/dsp/resample/cosine.hpp | 0 .../nall/dsp/resample/cubic.hpp | 0 .../nall/dsp/resample/hermite.hpp | 0 .../nall/dsp/resample/lib/sinc.hpp | 0 .../nall/dsp/resample/linear.hpp | 0 .../nall/dsp/resample/nearest.hpp | 0 .../nall/dsp/resample/sinc.hpp | 0 {snesfilter => kaijuu}/nall/dsp/settings.hpp | 0 kaijuu/nall/emulation/famicom.hpp | 182 +++ kaijuu/nall/emulation/game-boy-advance.hpp | 68 + .../nall/emulation/game-boy.hpp | 32 +- kaijuu/nall/emulation/satellaview.hpp | 26 + kaijuu/nall/emulation/sufami-turbo.hpp | 33 + kaijuu/nall/emulation/super-famicom-usart.hpp | 103 ++ kaijuu/nall/emulation/super-famicom.hpp | 800 ++++++++++ {snesfilter => kaijuu}/nall/endian.hpp | 0 {snesfilter => kaijuu}/nall/file.hpp | 75 +- {snesfilter => kaijuu}/nall/filemap.hpp | 1 + {snesfilter => kaijuu}/nall/function.hpp | 0 {snesfilter => kaijuu}/nall/gzip.hpp | 18 +- {snesfilter => kaijuu}/nall/http.hpp | 4 +- {snesfilter => kaijuu}/nall/image.hpp | 123 +- {snesfilter => kaijuu}/nall/inflate.hpp | 0 {snesfilter => kaijuu}/nall/input.hpp | 0 {snesfilter => kaijuu}/nall/interpolation.hpp | 8 +- {snesfilter => kaijuu}/nall/intrinsics.hpp | 0 kaijuu/nall/invoke.hpp | 52 + {snesfilter => kaijuu}/nall/ips.hpp | 10 - {snesfilter => kaijuu}/nall/lzss.hpp | 0 kaijuu/nall/map.hpp | 117 ++ kaijuu/nall/mosaic.hpp | 10 + kaijuu/nall/mosaic/bitstream.hpp | 55 + kaijuu/nall/mosaic/context.hpp | 224 +++ kaijuu/nall/mosaic/parser.hpp | 126 ++ kaijuu/nall/nall.hpp | 56 + kaijuu/nall/platform.hpp | 86 ++ {snesfilter => kaijuu}/nall/png.hpp | 10 +- .../nall/priority-queue.hpp | 4 +- {snesfilter => kaijuu}/nall/property.hpp | 0 .../nall/public-cast.hpp | 0 {snesfilter => kaijuu}/nall/random.hpp | 0 {snesfilter => kaijuu}/nall/serial.hpp | 29 +- {snesfilter => kaijuu}/nall/serializer.hpp | 4 +- kaijuu/nall/set.hpp | 158 ++ {snesfilter => kaijuu}/nall/sha256.hpp | 0 kaijuu/nall/sort.hpp | 77 + {snesfilter => kaijuu}/nall/stdint.hpp | 2 - kaijuu/nall/stream.hpp | 26 + kaijuu/nall/stream/auto.hpp | 25 + kaijuu/nall/stream/file.hpp | 42 + kaijuu/nall/stream/gzip.hpp | 34 + kaijuu/nall/stream/http.hpp | 49 + kaijuu/nall/stream/memory.hpp | 47 + kaijuu/nall/stream/mmap.hpp | 42 + kaijuu/nall/stream/stream.hpp | 92 ++ kaijuu/nall/stream/vector.hpp | 39 + kaijuu/nall/stream/zip.hpp | 38 + {snesfilter => kaijuu}/nall/string.hpp | 8 +- {snesfilter => kaijuu}/nall/string/base.hpp | 34 +- {snesfilter => kaijuu}/nall/string/bml.hpp | 6 +- {snesfilter => kaijuu}/nall/string/bsv.hpp | 0 {snesfilter => kaijuu}/nall/string/cast.hpp | 0 .../nall/string/compare.hpp | 0 .../nall/string/convert.hpp | 0 {snesfilter => kaijuu}/nall/string/core.hpp | 47 +- .../nall/string/cstring.hpp | 0 kaijuu/nall/string/filename.hpp | 74 + .../nall/string/math-fixed-point.hpp | 9 + .../nall/string/math-floating-point.hpp | 10 +- kaijuu/nall/string/platform.hpp | 63 + .../nall/string/replace.hpp | 0 {snesfilter => kaijuu}/nall/string/split.hpp | 0 kaijuu/nall/string/static.hpp | 13 + kaijuu/nall/string/strm.hpp | 45 + {snesfilter => kaijuu}/nall/string/strpos.hpp | 0 {snesfilter => kaijuu}/nall/string/trim.hpp | 0 kaijuu/nall/string/utf8.hpp | 43 + .../nall/string/utility.hpp | 16 +- .../nall/string/variadic.hpp | 0 .../nall/string/wildcard.hpp | 0 .../nall/string/wrapper.hpp | 1 + .../nall/string/xml-legacy.hpp | 0 kaijuu/nall/string/xml.hpp | 250 ++++ kaijuu/nall/traits.hpp | 33 + kaijuu/nall/udl.hpp | 28 + {snesfilter => kaijuu}/nall/ups.hpp | 0 {snesfilter => kaijuu}/nall/utility.hpp | 10 - kaijuu/nall/varint.hpp | 168 +++ kaijuu/nall/vector.hpp | 204 +++ .../nall/windows/detour.hpp | 0 kaijuu/nall/windows/guid.hpp | 30 + .../nall/windows/launcher.hpp | 0 kaijuu/nall/windows/registry.hpp | 120 ++ {snesfilter => kaijuu}/nall/windows/utf8.hpp | 1 + kaijuu/nall/xorg/guard.hpp | 29 + kaijuu/nall/xorg/xorg.hpp | 12 + {snesfilter => kaijuu}/nall/zip.hpp | 32 +- kaijuu/phoenix/Makefile | 21 + kaijuu/phoenix/core/core.cpp | 1326 +++++++++++++++++ kaijuu/phoenix/core/core.hpp | 612 ++++++++ kaijuu/phoenix/core/keyboard.hpp | 45 + kaijuu/phoenix/core/layout/fixed-layout.cpp | 80 + kaijuu/phoenix/core/layout/fixed-layout.hpp | 27 + .../phoenix/core/layout/horizontal-layout.cpp | 142 ++ .../phoenix/core/layout/horizontal-layout.hpp | 31 + .../phoenix/core/layout/vertical-layout.cpp | 142 ++ .../phoenix/core/layout/vertical-layout.hpp | 31 + kaijuu/phoenix/core/state.hpp | 278 ++++ kaijuu/phoenix/gtk/action/action.cpp | 27 + kaijuu/phoenix/gtk/action/check-item.cpp | 33 + kaijuu/phoenix/gtk/action/item.cpp | 31 + kaijuu/phoenix/gtk/action/menu.cpp | 51 + kaijuu/phoenix/gtk/action/radio-item.cpp | 48 + kaijuu/phoenix/gtk/action/separator.cpp | 12 + kaijuu/phoenix/gtk/desktop.cpp | 36 + kaijuu/phoenix/gtk/dialog-window.cpp | 69 + kaijuu/phoenix/gtk/font.cpp | 58 + kaijuu/phoenix/gtk/keyboard.cpp | 142 ++ kaijuu/phoenix/gtk/message-window.cpp | 61 + kaijuu/phoenix/gtk/mouse.cpp | 20 + kaijuu/phoenix/gtk/platform.cpp | 87 ++ kaijuu/phoenix/gtk/platform.hpp | 501 +++++++ kaijuu/phoenix/gtk/settings.cpp | 25 + kaijuu/phoenix/gtk/timer.cpp | 24 + kaijuu/phoenix/gtk/utility.cpp | 200 +++ kaijuu/phoenix/gtk/widget/button.cpp | 53 + kaijuu/phoenix/gtk/widget/canvas.cpp | 70 + kaijuu/phoenix/gtk/widget/check-box.cpp | 40 + kaijuu/phoenix/gtk/widget/combo-box.cpp | 73 + kaijuu/phoenix/gtk/widget/hex-edit.cpp | 264 ++++ .../gtk/widget/horizontal-scroll-bar.cpp | 42 + .../phoenix/gtk/widget/horizontal-slider.cpp | 41 + kaijuu/phoenix/gtk/widget/label.cpp | 24 + kaijuu/phoenix/gtk/widget/line-edit.cpp | 45 + kaijuu/phoenix/gtk/widget/list-view.cpp | 217 +++ kaijuu/phoenix/gtk/widget/progress-bar.cpp | 23 + kaijuu/phoenix/gtk/widget/radio-box.cpp | 50 + kaijuu/phoenix/gtk/widget/text-edit.cpp | 66 + .../gtk/widget/vertical-scroll-bar.cpp | 42 + kaijuu/phoenix/gtk/widget/vertical-slider.cpp | 41 + kaijuu/phoenix/gtk/widget/viewport.cpp | 58 + kaijuu/phoenix/gtk/widget/widget.cpp | 47 + kaijuu/phoenix/gtk/window.cpp | 352 +++++ kaijuu/phoenix/phoenix.cpp | 52 + kaijuu/phoenix/phoenix.hpp | 19 + kaijuu/phoenix/qt/action/action.cpp | 49 + kaijuu/phoenix/qt/action/check-item.cpp | 27 + kaijuu/phoenix/qt/action/item.cpp | 21 + kaijuu/phoenix/qt/action/menu.cpp | 51 + kaijuu/phoenix/qt/action/radio-item.cpp | 41 + kaijuu/phoenix/qt/action/separator.cpp | 9 + kaijuu/phoenix/qt/desktop.cpp | 9 + kaijuu/phoenix/qt/dialog-window.cpp | 57 + kaijuu/phoenix/qt/font.cpp | 40 + kaijuu/phoenix/qt/keyboard.cpp | 142 ++ kaijuu/phoenix/qt/message-window.cpp | 47 + kaijuu/phoenix/qt/mouse.cpp | 14 + kaijuu/phoenix/qt/platform.cpp | 91 ++ kaijuu/phoenix/qt/platform.moc | 1105 ++++++++++++++ kaijuu/phoenix/qt/platform.moc.hpp | 633 ++++++++ kaijuu/phoenix/qt/settings.cpp | 24 + kaijuu/phoenix/qt/timer.cpp | 25 + kaijuu/phoenix/qt/utility.cpp | 190 +++ kaijuu/phoenix/qt/widget/button.cpp | 52 + kaijuu/phoenix/qt/widget/canvas.cpp | 73 + kaijuu/phoenix/qt/widget/check-box.cpp | 42 + kaijuu/phoenix/qt/widget/combo-box.cpp | 68 + kaijuu/phoenix/qt/widget/hex-edit.cpp | 191 +++ .../qt/widget/horizontal-scroll-bar.cpp | 43 + .../phoenix/qt/widget/horizontal-slider.cpp | 43 + kaijuu/phoenix/qt/widget/label.cpp | 25 + kaijuu/phoenix/qt/widget/line-edit.cpp | 45 + kaijuu/phoenix/qt/widget/list-view.cpp | 164 ++ kaijuu/phoenix/qt/widget/progress-bar.cpp | 26 + kaijuu/phoenix/qt/widget/radio-box.cpp | 64 + kaijuu/phoenix/qt/widget/text-edit.cpp | 50 + .../phoenix/qt/widget/vertical-scroll-bar.cpp | 43 + kaijuu/phoenix/qt/widget/vertical-slider.cpp | 43 + kaijuu/phoenix/qt/widget/viewport.cpp | 51 + kaijuu/phoenix/qt/widget/widget.cpp | 52 + kaijuu/phoenix/qt/window.cpp | 288 ++++ kaijuu/phoenix/reference/action/action.cpp | 8 + .../phoenix/reference/action/check-item.cpp | 15 + kaijuu/phoenix/reference/action/item.cpp | 11 + kaijuu/phoenix/reference/action/menu.cpp | 17 + .../phoenix/reference/action/radio-item.cpp | 18 + kaijuu/phoenix/reference/action/separator.cpp | 5 + kaijuu/phoenix/reference/desktop.cpp | 8 + kaijuu/phoenix/reference/dialog-window.cpp | 11 + kaijuu/phoenix/reference/font.cpp | 3 + kaijuu/phoenix/reference/keyboard.cpp | 10 + kaijuu/phoenix/reference/message-window.cpp | 15 + kaijuu/phoenix/reference/mouse.cpp | 7 + kaijuu/phoenix/reference/platform.cpp | 52 + kaijuu/phoenix/reference/platform.hpp | 381 +++++ kaijuu/phoenix/reference/timer.cpp | 8 + kaijuu/phoenix/reference/widget/button.cpp | 8 + kaijuu/phoenix/reference/widget/canvas.cpp | 8 + kaijuu/phoenix/reference/widget/check-box.cpp | 12 + kaijuu/phoenix/reference/widget/combo-box.cpp | 21 + kaijuu/phoenix/reference/widget/hex-edit.cpp | 17 + .../widget/horizontal-scroll-bar.cpp | 12 + .../reference/widget/horizontal-slider.cpp | 12 + kaijuu/phoenix/reference/widget/label.cpp | 5 + kaijuu/phoenix/reference/widget/line-edit.cpp | 11 + kaijuu/phoenix/reference/widget/list-view.cpp | 49 + .../phoenix/reference/widget/progress-bar.cpp | 5 + kaijuu/phoenix/reference/widget/radio-box.cpp | 15 + kaijuu/phoenix/reference/widget/text-edit.cpp | 17 + .../reference/widget/vertical-scroll-bar.cpp | 12 + .../reference/widget/vertical-slider.cpp | 12 + kaijuu/phoenix/reference/widget/viewport.cpp | 6 + kaijuu/phoenix/reference/widget/widget.cpp | 25 + kaijuu/phoenix/reference/window.cpp | 78 + {snesfilter => kaijuu/phoenix}/sync.sh | 1 + kaijuu/phoenix/windows/action/action.cpp | 12 + kaijuu/phoenix/windows/action/check-item.cpp | 18 + kaijuu/phoenix/windows/action/item.cpp | 29 + kaijuu/phoenix/windows/action/menu.cpp | 109 ++ kaijuu/phoenix/windows/action/radio-item.cpp | 26 + kaijuu/phoenix/windows/action/separator.cpp | 6 + kaijuu/phoenix/windows/desktop.cpp | 9 + kaijuu/phoenix/windows/dialog-window.cpp | 88 ++ kaijuu/phoenix/windows/font.cpp | 44 + kaijuu/phoenix/windows/keyboard.cpp | 137 ++ kaijuu/phoenix/windows/message-window.cpp | 41 + kaijuu/phoenix/windows/mouse.cpp | 14 + kaijuu/phoenix/windows/object.cpp | 13 + kaijuu/phoenix/windows/phoenix.Manifest | 14 + kaijuu/phoenix/windows/phoenix.rc | 1 + kaijuu/phoenix/windows/platform.cpp | 479 ++++++ kaijuu/phoenix/windows/platform.hpp | 481 ++++++ kaijuu/phoenix/windows/settings.cpp | 1 + kaijuu/phoenix/windows/timer.cpp | 31 + kaijuu/phoenix/windows/utility.cpp | 150 ++ kaijuu/phoenix/windows/widget/button.cpp | 90 ++ kaijuu/phoenix/windows/widget/canvas.cpp | 92 ++ kaijuu/phoenix/windows/widget/check-box.cpp | 39 + kaijuu/phoenix/windows/widget/combo-box.cpp | 70 + kaijuu/phoenix/windows/widget/hex-edit.cpp | 136 ++ .../windows/widget/horizontal-scroll-bar.cpp | 38 + .../windows/widget/horizontal-slider.cpp | 39 + kaijuu/phoenix/windows/widget/label.cpp | 64 + kaijuu/phoenix/windows/widget/line-edit.cpp | 45 + kaijuu/phoenix/windows/widget/list-view.cpp | 210 +++ .../phoenix/windows/widget/progress-bar.cpp | 25 + kaijuu/phoenix/windows/widget/radio-box.cpp | 43 + kaijuu/phoenix/windows/widget/text-edit.cpp | 58 + .../windows/widget/vertical-scroll-bar.cpp | 38 + .../windows/widget/vertical-slider.cpp | 39 + kaijuu/phoenix/windows/widget/viewport.cpp | 57 + kaijuu/phoenix/windows/widget/widget.cpp | 66 + kaijuu/phoenix/windows/window.cpp | 229 +++ kaijuu/resource/kaijuu.png | Bin 0 -> 13013 bytes kaijuu/resource/resource.cpp | 413 +++++ kaijuu/resource/resource.hpp | 3 + kaijuu/resource/resource.xml | 4 + kaijuu/settings.hpp | 45 + kaijuu/sync.sh | 7 + purify/Makefile | 6 +- purify/nall/Makefile | 3 + purify/nall/algorithm.hpp | 0 purify/nall/any.hpp | 0 purify/nall/atoi.hpp | 0 purify/nall/base64.hpp | 0 purify/nall/bit.hpp | 0 purify/nall/bmp.hpp | 0 purify/nall/bps/delta.hpp | 0 purify/nall/bps/linear.hpp | 0 purify/nall/bps/metadata.hpp | 0 purify/nall/bps/patch.hpp | 0 purify/nall/compositor.hpp | 0 purify/nall/config.hpp | 0 purify/nall/crc32.hpp | 0 purify/nall/directory.hpp | 0 purify/nall/dl.hpp | 0 purify/nall/dsp.hpp | 0 purify/nall/dsp/buffer.hpp | 0 purify/nall/dsp/core.hpp | 0 purify/nall/dsp/resample/average.hpp | 0 purify/nall/dsp/resample/cosine.hpp | 0 purify/nall/dsp/resample/cubic.hpp | 0 purify/nall/dsp/resample/hermite.hpp | 0 purify/nall/dsp/resample/lib/sinc.hpp | 0 purify/nall/dsp/resample/linear.hpp | 0 purify/nall/dsp/resample/nearest.hpp | 0 purify/nall/dsp/resample/sinc.hpp | 0 purify/nall/dsp/settings.hpp | 0 purify/nall/emulation/famicom.hpp | 0 purify/nall/emulation/game-boy-advance.hpp | 0 purify/nall/emulation/game-boy.hpp | 0 purify/nall/emulation/satellaview.hpp | 0 purify/nall/emulation/sufami-turbo.hpp | 0 purify/nall/emulation/super-famicom-usart.hpp | 0 purify/nall/emulation/super-famicom.hpp | 3 + purify/nall/endian.hpp | 0 purify/nall/file.hpp | 0 purify/nall/filemap.hpp | 0 purify/nall/function.hpp | 0 purify/nall/gzip.hpp | 0 purify/nall/http.hpp | 0 purify/nall/image.hpp | 0 purify/nall/inflate.hpp | 0 purify/nall/input.hpp | 0 purify/nall/interpolation.hpp | 0 purify/nall/intrinsics.hpp | 0 purify/nall/invoke.hpp | 0 purify/nall/ips.hpp | 0 purify/nall/lzss.hpp | 0 purify/nall/map.hpp | 0 purify/nall/mosaic.hpp | 0 purify/nall/mosaic/bitstream.hpp | 0 purify/nall/mosaic/context.hpp | 0 purify/nall/mosaic/parser.hpp | 0 purify/nall/nall.hpp | 0 purify/nall/platform.hpp | 0 purify/nall/png.hpp | 0 purify/nall/priority-queue.hpp | 0 purify/nall/property.hpp | 0 purify/nall/public-cast.hpp | 0 purify/nall/random.hpp | 0 purify/nall/serial.hpp | 0 purify/nall/serializer.hpp | 0 purify/nall/set.hpp | 0 purify/nall/sha256.hpp | 0 purify/nall/sort.hpp | 0 purify/nall/stdint.hpp | 0 purify/nall/stream.hpp | 0 purify/nall/stream/auto.hpp | 0 purify/nall/stream/file.hpp | 0 purify/nall/stream/gzip.hpp | 0 purify/nall/stream/http.hpp | 0 purify/nall/stream/memory.hpp | 0 purify/nall/stream/mmap.hpp | 0 purify/nall/stream/stream.hpp | 0 purify/nall/stream/vector.hpp | 0 purify/nall/stream/zip.hpp | 0 purify/nall/string.hpp | 0 purify/nall/string/base.hpp | 0 purify/nall/string/bml.hpp | 0 purify/nall/string/bsv.hpp | 0 purify/nall/string/cast.hpp | 0 purify/nall/string/compare.hpp | 0 purify/nall/string/convert.hpp | 0 purify/nall/string/core.hpp | 0 purify/nall/string/cstring.hpp | 0 purify/nall/string/filename.hpp | 0 purify/nall/string/math-fixed-point.hpp | 0 purify/nall/string/math-floating-point.hpp | 0 purify/nall/string/platform.hpp | 0 purify/nall/string/replace.hpp | 0 purify/nall/string/split.hpp | 0 purify/nall/string/static.hpp | 0 purify/nall/string/strm.hpp | 0 purify/nall/string/strpos.hpp | 0 purify/nall/string/trim.hpp | 0 purify/nall/string/utf8.hpp | 0 purify/nall/string/utility.hpp | 0 purify/nall/string/variadic.hpp | 0 purify/nall/string/wildcard.hpp | 0 purify/nall/string/wrapper.hpp | 0 purify/nall/string/xml-legacy.hpp | 0 purify/nall/string/xml.hpp | 0 purify/nall/traits.hpp | 0 purify/nall/udl.hpp | 0 purify/nall/ups.hpp | 0 purify/nall/utility.hpp | 0 purify/nall/varint.hpp | 0 purify/nall/vector.hpp | 0 purify/nall/windows/detour.hpp | 0 purify/nall/windows/guid.hpp | 0 purify/nall/windows/launcher.hpp | 0 purify/nall/windows/registry.hpp | 0 purify/nall/windows/utf8.hpp | 0 purify/nall/xorg/guard.hpp | 0 purify/nall/xorg/xorg.hpp | 0 purify/nall/zip.hpp | 0 purify/phoenix/Makefile | 0 purify/phoenix/core/core.cpp | 0 purify/phoenix/core/core.hpp | 0 purify/phoenix/core/keyboard.hpp | 0 purify/phoenix/core/layout/fixed-layout.cpp | 0 purify/phoenix/core/layout/fixed-layout.hpp | 0 .../phoenix/core/layout/horizontal-layout.cpp | 0 .../phoenix/core/layout/horizontal-layout.hpp | 0 .../phoenix/core/layout/vertical-layout.cpp | 0 .../phoenix/core/layout/vertical-layout.hpp | 0 purify/phoenix/core/state.hpp | 0 purify/phoenix/gtk/action/action.cpp | 0 purify/phoenix/gtk/action/check-item.cpp | 0 purify/phoenix/gtk/action/item.cpp | 0 purify/phoenix/gtk/action/menu.cpp | 0 purify/phoenix/gtk/action/radio-item.cpp | 0 purify/phoenix/gtk/action/separator.cpp | 0 purify/phoenix/gtk/desktop.cpp | 0 purify/phoenix/gtk/dialog-window.cpp | 0 purify/phoenix/gtk/font.cpp | 0 purify/phoenix/gtk/keyboard.cpp | 0 purify/phoenix/gtk/message-window.cpp | 0 purify/phoenix/gtk/mouse.cpp | 0 purify/phoenix/gtk/platform.cpp | 0 purify/phoenix/gtk/platform.hpp | 0 purify/phoenix/gtk/settings.cpp | 0 purify/phoenix/gtk/timer.cpp | 0 purify/phoenix/gtk/utility.cpp | 0 purify/phoenix/gtk/widget/button.cpp | 0 purify/phoenix/gtk/widget/canvas.cpp | 0 purify/phoenix/gtk/widget/check-box.cpp | 0 purify/phoenix/gtk/widget/combo-box.cpp | 0 purify/phoenix/gtk/widget/hex-edit.cpp | 0 .../gtk/widget/horizontal-scroll-bar.cpp | 0 .../phoenix/gtk/widget/horizontal-slider.cpp | 0 purify/phoenix/gtk/widget/label.cpp | 0 purify/phoenix/gtk/widget/line-edit.cpp | 0 purify/phoenix/gtk/widget/list-view.cpp | 0 purify/phoenix/gtk/widget/progress-bar.cpp | 0 purify/phoenix/gtk/widget/radio-box.cpp | 0 purify/phoenix/gtk/widget/text-edit.cpp | 0 .../gtk/widget/vertical-scroll-bar.cpp | 0 purify/phoenix/gtk/widget/vertical-slider.cpp | 0 purify/phoenix/gtk/widget/viewport.cpp | 0 purify/phoenix/gtk/widget/widget.cpp | 0 purify/phoenix/gtk/window.cpp | 0 purify/phoenix/phoenix.cpp | 0 purify/phoenix/phoenix.hpp | 0 purify/phoenix/qt/action/action.cpp | 0 purify/phoenix/qt/action/check-item.cpp | 0 purify/phoenix/qt/action/item.cpp | 0 purify/phoenix/qt/action/menu.cpp | 0 purify/phoenix/qt/action/radio-item.cpp | 0 purify/phoenix/qt/action/separator.cpp | 0 purify/phoenix/qt/desktop.cpp | 0 purify/phoenix/qt/dialog-window.cpp | 0 purify/phoenix/qt/font.cpp | 0 purify/phoenix/qt/keyboard.cpp | 0 purify/phoenix/qt/message-window.cpp | 0 purify/phoenix/qt/mouse.cpp | 0 purify/phoenix/qt/platform.cpp | 0 purify/phoenix/qt/platform.moc | 0 purify/phoenix/qt/platform.moc.hpp | 0 purify/phoenix/qt/settings.cpp | 0 purify/phoenix/qt/timer.cpp | 0 purify/phoenix/qt/utility.cpp | 0 purify/phoenix/qt/widget/button.cpp | 0 purify/phoenix/qt/widget/canvas.cpp | 0 purify/phoenix/qt/widget/check-box.cpp | 0 purify/phoenix/qt/widget/combo-box.cpp | 0 purify/phoenix/qt/widget/hex-edit.cpp | 0 .../qt/widget/horizontal-scroll-bar.cpp | 0 .../phoenix/qt/widget/horizontal-slider.cpp | 0 purify/phoenix/qt/widget/label.cpp | 0 purify/phoenix/qt/widget/line-edit.cpp | 0 purify/phoenix/qt/widget/list-view.cpp | 0 purify/phoenix/qt/widget/progress-bar.cpp | 0 purify/phoenix/qt/widget/radio-box.cpp | 0 purify/phoenix/qt/widget/text-edit.cpp | 0 .../phoenix/qt/widget/vertical-scroll-bar.cpp | 0 purify/phoenix/qt/widget/vertical-slider.cpp | 0 purify/phoenix/qt/widget/viewport.cpp | 0 purify/phoenix/qt/widget/widget.cpp | 0 purify/phoenix/qt/window.cpp | 0 purify/phoenix/reference/action/action.cpp | 0 .../phoenix/reference/action/check-item.cpp | 0 purify/phoenix/reference/action/item.cpp | 0 purify/phoenix/reference/action/menu.cpp | 0 .../phoenix/reference/action/radio-item.cpp | 0 purify/phoenix/reference/action/separator.cpp | 0 purify/phoenix/reference/desktop.cpp | 0 purify/phoenix/reference/dialog-window.cpp | 0 purify/phoenix/reference/font.cpp | 0 purify/phoenix/reference/keyboard.cpp | 0 purify/phoenix/reference/message-window.cpp | 0 purify/phoenix/reference/mouse.cpp | 0 purify/phoenix/reference/platform.cpp | 0 purify/phoenix/reference/platform.hpp | 0 purify/phoenix/reference/timer.cpp | 0 purify/phoenix/reference/widget/button.cpp | 0 purify/phoenix/reference/widget/canvas.cpp | 0 purify/phoenix/reference/widget/check-box.cpp | 0 purify/phoenix/reference/widget/combo-box.cpp | 0 purify/phoenix/reference/widget/hex-edit.cpp | 0 .../widget/horizontal-scroll-bar.cpp | 0 .../reference/widget/horizontal-slider.cpp | 0 purify/phoenix/reference/widget/label.cpp | 0 purify/phoenix/reference/widget/line-edit.cpp | 0 purify/phoenix/reference/widget/list-view.cpp | 0 .../phoenix/reference/widget/progress-bar.cpp | 0 purify/phoenix/reference/widget/radio-box.cpp | 0 purify/phoenix/reference/widget/text-edit.cpp | 0 .../reference/widget/vertical-scroll-bar.cpp | 0 .../reference/widget/vertical-slider.cpp | 0 purify/phoenix/reference/widget/viewport.cpp | 0 purify/phoenix/reference/widget/widget.cpp | 0 purify/phoenix/reference/window.cpp | 0 purify/phoenix/sync.sh | 0 purify/phoenix/windows/action/action.cpp | 0 purify/phoenix/windows/action/check-item.cpp | 0 purify/phoenix/windows/action/item.cpp | 0 purify/phoenix/windows/action/menu.cpp | 0 purify/phoenix/windows/action/radio-item.cpp | 0 purify/phoenix/windows/action/separator.cpp | 0 purify/phoenix/windows/desktop.cpp | 0 purify/phoenix/windows/dialog-window.cpp | 0 purify/phoenix/windows/font.cpp | 0 purify/phoenix/windows/keyboard.cpp | 0 purify/phoenix/windows/message-window.cpp | 0 purify/phoenix/windows/mouse.cpp | 0 purify/phoenix/windows/object.cpp | 0 purify/phoenix/windows/phoenix.Manifest | 0 purify/phoenix/windows/phoenix.rc | 0 purify/phoenix/windows/platform.cpp | 0 purify/phoenix/windows/platform.hpp | 0 purify/phoenix/windows/settings.cpp | 0 purify/phoenix/windows/timer.cpp | 0 purify/phoenix/windows/utility.cpp | 0 purify/phoenix/windows/widget/button.cpp | 0 purify/phoenix/windows/widget/canvas.cpp | 0 purify/phoenix/windows/widget/check-box.cpp | 0 purify/phoenix/windows/widget/combo-box.cpp | 0 purify/phoenix/windows/widget/hex-edit.cpp | 0 .../windows/widget/horizontal-scroll-bar.cpp | 0 .../windows/widget/horizontal-slider.cpp | 0 purify/phoenix/windows/widget/label.cpp | 0 purify/phoenix/windows/widget/line-edit.cpp | 0 purify/phoenix/windows/widget/list-view.cpp | 0 .../phoenix/windows/widget/progress-bar.cpp | 0 purify/phoenix/windows/widget/radio-box.cpp | 0 purify/phoenix/windows/widget/text-edit.cpp | 0 .../windows/widget/vertical-scroll-bar.cpp | 0 .../windows/widget/vertical-slider.cpp | 0 purify/phoenix/windows/widget/viewport.cpp | 0 purify/phoenix/windows/widget/widget.cpp | 0 purify/phoenix/windows/window.cpp | 0 purify/purify.cpp | 2 +- purify/resource/applications-system.png | Bin purify/resource/drive-harddisk.png | Bin purify/resource/folder.png | Bin purify/resource/input-gaming.png | Bin purify/resource/resource.cpp | 0 purify/resource/resource.hpp | 0 purify/resource/resource.xml | 0 purify/resource/view-refresh.png | Bin snesfilter/HQ2x/HQ2x-RGB555.cpp | 206 --- snesfilter/HQ2x/HQ2x.cpp | 214 --- snesfilter/LQ2x/LQ2x.cpp | 52 - snesfilter/Makefile | 43 - snesfilter/Phosphor3x/Phosphor3x.cpp | 58 - snesfilter/Pixellate2x/Pixellate2x.cpp | 36 - snesfilter/Scale2x/Scale2x.cpp | 51 - snesfilter/Scanline/Scanline-Dark.cpp | 32 - snesfilter/Scanline/Scanline-Light.cpp | 33 - snesfilter/nall/array.hpp | 141 -- snesfilter/nall/bit.hpp | 51 - snesfilter/nall/moduloarray.hpp | 40 - snesfilter/nall/platform.hpp | 142 -- snesfilter/nall/reference_array.hpp | 142 -- snesfilter/nall/resource.hpp | 61 - snesfilter/nall/snes/cartridge.hpp | 792 ---------- snesfilter/nall/snes/cpu.hpp | 458 ------ snesfilter/nall/snes/smp.hpp | 639 -------- snesfilter/nall/sort.hpp | 62 - snesfilter/nall/stack.hpp | 26 - snesfilter/nall/static.hpp | 20 - snesfilter/nall/string/filename.hpp | 62 - snesfilter/nall/string/math.hpp | 167 --- snesfilter/nall/string/platform.hpp | 39 - snesfilter/nall/string/strl.hpp | 51 - snesfilter/nall/test/cc.bat | 2 - snesfilter/nall/test/cc.sh | 2 - snesfilter/nall/test/document.bml | 14 - snesfilter/nall/test/test | Bin 250304 -> 0 bytes snesfilter/nall/test/test.cpp | 90 -- snesfilter/nall/varint.hpp | 121 -- snesfilter/nall/vector.hpp | 414 ----- snesfilter/out/.gitignore | 1 - snesshader/Archive/HDR-TV.OpenGL.shader | 17 - snesshader/Archive/Watercolor.OpenGL.shader | 61 - snesshader/Curvature.OpenGL.shader | 22 - snesshader/HQ2x.OpenGL.shader | 73 - snesshader/Makefile | 4 - snesshader/Pixellate.OpenGL.shader | 44 - snesshader/Scale2x.OpenGL.shader | 55 - snesshader/Sepia.Direct3D.shader | 30 - 1613 files changed, 31738 insertions(+), 4846 deletions(-) mode change 100755 => 100644 bsnes/Makefile mode change 100755 => 100644 bsnes/data/bsnes.Manifest mode change 100755 => 100644 bsnes/data/bsnes.desktop mode change 100755 => 100644 bsnes/data/bsnes.ico mode change 100755 => 100644 bsnes/data/bsnes.png mode change 100755 => 100644 bsnes/data/cheats.xml mode change 100755 => 100644 bsnes/data/laevateinn.hpp mode change 100755 => 100644 bsnes/emulator/emulator.hpp mode change 100755 => 100644 bsnes/emulator/interface.hpp mode change 100755 => 100644 bsnes/fc/Makefile mode change 100755 => 100644 bsnes/fc/apu/apu.cpp mode change 100755 => 100644 bsnes/fc/apu/apu.hpp mode change 100755 => 100644 bsnes/fc/apu/dmc.cpp mode change 100755 => 100644 bsnes/fc/apu/dmc.hpp mode change 100755 => 100644 bsnes/fc/apu/envelope.cpp mode change 100755 => 100644 bsnes/fc/apu/envelope.hpp mode change 100755 => 100644 bsnes/fc/apu/noise.cpp mode change 100755 => 100644 bsnes/fc/apu/noise.hpp mode change 100755 => 100644 bsnes/fc/apu/pulse.cpp mode change 100755 => 100644 bsnes/fc/apu/pulse.hpp mode change 100755 => 100644 bsnes/fc/apu/serialization.cpp mode change 100755 => 100644 bsnes/fc/apu/sweep.cpp mode change 100755 => 100644 bsnes/fc/apu/sweep.hpp mode change 100755 => 100644 bsnes/fc/apu/triangle.cpp mode change 100755 => 100644 bsnes/fc/apu/triangle.hpp mode change 100755 => 100644 bsnes/fc/cartridge/board/bandai-fcg.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/board.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/board.hpp mode change 100755 => 100644 bsnes/fc/cartridge/board/konami-vrc1.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/konami-vrc2.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/konami-vrc3.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/konami-vrc4.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/konami-vrc6.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/konami-vrc7.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-axrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-bnrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-cnrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-exrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-fxrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-gxrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-hkrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-nrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-pxrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-sxrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-txrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/nes-uxrom.cpp mode change 100755 => 100644 bsnes/fc/cartridge/board/sunsoft-5b.cpp mode change 100755 => 100644 bsnes/fc/cartridge/cartridge.cpp mode change 100755 => 100644 bsnes/fc/cartridge/cartridge.hpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/chip.cpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/chip.hpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/mmc1.cpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/mmc3.cpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/mmc5.cpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/mmc6.cpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/vrc1.cpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/vrc2.cpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/vrc3.cpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/vrc4.cpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/vrc6.cpp mode change 100755 => 100644 bsnes/fc/cartridge/chip/vrc7.cpp mode change 100755 => 100644 bsnes/fc/cheat/cheat.cpp mode change 100755 => 100644 bsnes/fc/cheat/cheat.hpp mode change 100755 => 100644 bsnes/fc/cpu/cpu.cpp mode change 100755 => 100644 bsnes/fc/cpu/cpu.hpp mode change 100755 => 100644 bsnes/fc/cpu/serialization.cpp mode change 100755 => 100644 bsnes/fc/cpu/timing.cpp mode change 100755 => 100644 bsnes/fc/fc.hpp mode change 100755 => 100644 bsnes/fc/input/input.cpp mode change 100755 => 100644 bsnes/fc/input/input.hpp mode change 100755 => 100644 bsnes/fc/input/serialization.cpp mode change 100755 => 100644 bsnes/fc/interface/interface.cpp mode change 100755 => 100644 bsnes/fc/interface/interface.hpp mode change 100755 => 100644 bsnes/fc/memory/memory.cpp mode change 100755 => 100644 bsnes/fc/memory/memory.hpp mode change 100755 => 100644 bsnes/fc/ppu/ppu.cpp mode change 100755 => 100644 bsnes/fc/ppu/ppu.hpp mode change 100755 => 100644 bsnes/fc/ppu/serialization.cpp mode change 100755 => 100644 bsnes/fc/scheduler/scheduler.cpp mode change 100755 => 100644 bsnes/fc/scheduler/scheduler.hpp mode change 100755 => 100644 bsnes/fc/system/serialization.cpp mode change 100755 => 100644 bsnes/fc/system/system.cpp mode change 100755 => 100644 bsnes/fc/system/system.hpp mode change 100755 => 100644 bsnes/fc/video/video.cpp mode change 100755 => 100644 bsnes/fc/video/video.hpp mode change 100755 => 100644 bsnes/gb/Makefile mode change 100755 => 100644 bsnes/gb/apu/apu.cpp mode change 100755 => 100644 bsnes/gb/apu/apu.hpp mode change 100755 => 100644 bsnes/gb/apu/master/master.cpp mode change 100755 => 100644 bsnes/gb/apu/master/master.hpp mode change 100755 => 100644 bsnes/gb/apu/noise/noise.cpp mode change 100755 => 100644 bsnes/gb/apu/noise/noise.hpp mode change 100755 => 100644 bsnes/gb/apu/serialization.cpp mode change 100755 => 100644 bsnes/gb/apu/square1/square1.cpp mode change 100755 => 100644 bsnes/gb/apu/square1/square1.hpp mode change 100755 => 100644 bsnes/gb/apu/square2/square2.cpp mode change 100755 => 100644 bsnes/gb/apu/square2/square2.hpp mode change 100755 => 100644 bsnes/gb/apu/wave/wave.cpp mode change 100755 => 100644 bsnes/gb/apu/wave/wave.hpp mode change 100755 => 100644 bsnes/gb/cartridge/cartridge.cpp mode change 100755 => 100644 bsnes/gb/cartridge/cartridge.hpp mode change 100755 => 100644 bsnes/gb/cartridge/huc1/huc1.cpp mode change 100755 => 100644 bsnes/gb/cartridge/huc1/huc1.hpp mode change 100755 => 100644 bsnes/gb/cartridge/huc3/huc3.cpp mode change 100755 => 100644 bsnes/gb/cartridge/huc3/huc3.hpp mode change 100755 => 100644 bsnes/gb/cartridge/mbc0/mbc0.cpp mode change 100755 => 100644 bsnes/gb/cartridge/mbc0/mbc0.hpp mode change 100755 => 100644 bsnes/gb/cartridge/mbc1/mbc1.cpp mode change 100755 => 100644 bsnes/gb/cartridge/mbc1/mbc1.hpp mode change 100755 => 100644 bsnes/gb/cartridge/mbc2/mbc2.cpp mode change 100755 => 100644 bsnes/gb/cartridge/mbc2/mbc2.hpp mode change 100755 => 100644 bsnes/gb/cartridge/mbc3/mbc3.cpp mode change 100755 => 100644 bsnes/gb/cartridge/mbc3/mbc3.hpp mode change 100755 => 100644 bsnes/gb/cartridge/mbc5/mbc5.cpp mode change 100755 => 100644 bsnes/gb/cartridge/mbc5/mbc5.hpp mode change 100755 => 100644 bsnes/gb/cartridge/mmm01/mmm01.cpp mode change 100755 => 100644 bsnes/gb/cartridge/mmm01/mmm01.hpp mode change 100755 => 100644 bsnes/gb/cartridge/serialization.cpp mode change 100755 => 100644 bsnes/gb/cheat/cheat.cpp mode change 100755 => 100644 bsnes/gb/cheat/cheat.hpp mode change 100755 => 100644 bsnes/gb/cpu/cpu.cpp mode change 100755 => 100644 bsnes/gb/cpu/cpu.hpp mode change 100755 => 100644 bsnes/gb/cpu/memory.cpp mode change 100755 => 100644 bsnes/gb/cpu/mmio.cpp mode change 100755 => 100644 bsnes/gb/cpu/serialization.cpp mode change 100755 => 100644 bsnes/gb/cpu/timing.cpp mode change 100755 => 100644 bsnes/gb/gb.hpp mode change 100755 => 100644 bsnes/gb/interface/interface.cpp mode change 100755 => 100644 bsnes/gb/interface/interface.hpp mode change 100755 => 100644 bsnes/gb/memory/memory.cpp mode change 100755 => 100644 bsnes/gb/memory/memory.hpp mode change 100755 => 100644 bsnes/gb/ppu/cgb.cpp mode change 100755 => 100644 bsnes/gb/ppu/dmg.cpp mode change 100755 => 100644 bsnes/gb/ppu/mmio.cpp mode change 100755 => 100644 bsnes/gb/ppu/ppu.cpp mode change 100755 => 100644 bsnes/gb/ppu/ppu.hpp mode change 100755 => 100644 bsnes/gb/ppu/serialization.cpp mode change 100755 => 100644 bsnes/gb/scheduler/scheduler.cpp mode change 100755 => 100644 bsnes/gb/scheduler/scheduler.hpp mode change 100755 => 100644 bsnes/gb/system/serialization.cpp mode change 100755 => 100644 bsnes/gb/system/system.cpp mode change 100755 => 100644 bsnes/gb/system/system.hpp mode change 100755 => 100644 bsnes/gb/video/video.cpp mode change 100755 => 100644 bsnes/gb/video/video.hpp mode change 100755 => 100644 bsnes/gba/Makefile mode change 100755 => 100644 bsnes/gba/apu/apu.cpp mode change 100755 => 100644 bsnes/gba/apu/apu.hpp mode change 100755 => 100644 bsnes/gba/apu/fifo.cpp mode change 100755 => 100644 bsnes/gba/apu/mmio.cpp mode change 100755 => 100644 bsnes/gba/apu/noise.cpp mode change 100755 => 100644 bsnes/gba/apu/registers.cpp mode change 100755 => 100644 bsnes/gba/apu/registers.hpp mode change 100755 => 100644 bsnes/gba/apu/sequencer.cpp mode change 100755 => 100644 bsnes/gba/apu/serialization.cpp mode change 100755 => 100644 bsnes/gba/apu/square.cpp mode change 100755 => 100644 bsnes/gba/apu/square1.cpp mode change 100755 => 100644 bsnes/gba/apu/square2.cpp mode change 100755 => 100644 bsnes/gba/apu/wave.cpp mode change 100755 => 100644 bsnes/gba/cartridge/cartridge.cpp mode change 100755 => 100644 bsnes/gba/cartridge/cartridge.hpp mode change 100755 => 100644 bsnes/gba/cartridge/eeprom.cpp mode change 100755 => 100644 bsnes/gba/cartridge/flashrom.cpp mode change 100755 => 100644 bsnes/gba/cartridge/memory.hpp mode change 100755 => 100644 bsnes/gba/cartridge/serialization.cpp mode change 100755 => 100644 bsnes/gba/cpu/cpu.cpp mode change 100755 => 100644 bsnes/gba/cpu/cpu.hpp mode change 100755 => 100644 bsnes/gba/cpu/dma.cpp mode change 100755 => 100644 bsnes/gba/cpu/memory.cpp mode change 100755 => 100644 bsnes/gba/cpu/mmio.cpp mode change 100755 => 100644 bsnes/gba/cpu/registers.cpp mode change 100755 => 100644 bsnes/gba/cpu/registers.hpp mode change 100755 => 100644 bsnes/gba/cpu/serialization.cpp mode change 100755 => 100644 bsnes/gba/cpu/state.hpp mode change 100755 => 100644 bsnes/gba/cpu/timer.cpp mode change 100755 => 100644 bsnes/gba/gba.hpp mode change 100755 => 100644 bsnes/gba/interface/interface.cpp mode change 100755 => 100644 bsnes/gba/interface/interface.hpp mode change 100755 => 100644 bsnes/gba/memory/memory.cpp mode change 100755 => 100644 bsnes/gba/memory/memory.hpp mode change 100755 => 100644 bsnes/gba/memory/mmio.cpp mode change 100755 => 100644 bsnes/gba/memory/serialization.cpp mode change 100755 => 100644 bsnes/gba/ppu/background.cpp mode change 100755 => 100644 bsnes/gba/ppu/memory.cpp mode change 100755 => 100644 bsnes/gba/ppu/mmio.cpp mode change 100755 => 100644 bsnes/gba/ppu/mosaic.cpp mode change 100755 => 100644 bsnes/gba/ppu/object.cpp mode change 100755 => 100644 bsnes/gba/ppu/ppu.cpp mode change 100755 => 100644 bsnes/gba/ppu/ppu.hpp mode change 100755 => 100644 bsnes/gba/ppu/registers.cpp mode change 100755 => 100644 bsnes/gba/ppu/registers.hpp mode change 100755 => 100644 bsnes/gba/ppu/screen.cpp mode change 100755 => 100644 bsnes/gba/ppu/serialization.cpp mode change 100755 => 100644 bsnes/gba/ppu/state.hpp mode change 100755 => 100644 bsnes/gba/scheduler/scheduler.cpp mode change 100755 => 100644 bsnes/gba/scheduler/scheduler.hpp mode change 100755 => 100644 bsnes/gba/system/bios.cpp mode change 100755 => 100644 bsnes/gba/system/serialization.cpp mode change 100755 => 100644 bsnes/gba/system/system.cpp mode change 100755 => 100644 bsnes/gba/system/system.hpp mode change 100755 => 100644 bsnes/gba/video/video.cpp mode change 100755 => 100644 bsnes/gba/video/video.hpp mode change 100755 => 100644 bsnes/libco/amd64.c mode change 100755 => 100644 bsnes/libco/fiber.c mode change 100755 => 100644 bsnes/libco/libco.c mode change 100755 => 100644 bsnes/libco/libco.h mode change 100755 => 100644 bsnes/libco/ppc.c mode change 100755 => 100644 bsnes/libco/sjlj.c mode change 100755 => 100644 bsnes/libco/ucontext.c mode change 100755 => 100644 bsnes/libco/x86.c mode change 100755 => 100644 bsnes/nall/Makefile mode change 100755 => 100644 bsnes/nall/algorithm.hpp mode change 100755 => 100644 bsnes/nall/any.hpp mode change 100755 => 100644 bsnes/nall/atoi.hpp mode change 100755 => 100644 bsnes/nall/base64.hpp mode change 100755 => 100644 bsnes/nall/bit.hpp mode change 100755 => 100644 bsnes/nall/bmp.hpp mode change 100755 => 100644 bsnes/nall/bps/delta.hpp mode change 100755 => 100644 bsnes/nall/bps/linear.hpp mode change 100755 => 100644 bsnes/nall/bps/metadata.hpp mode change 100755 => 100644 bsnes/nall/bps/patch.hpp mode change 100755 => 100644 bsnes/nall/compositor.hpp mode change 100755 => 100644 bsnes/nall/config.hpp mode change 100755 => 100644 bsnes/nall/crc32.hpp mode change 100755 => 100644 bsnes/nall/directory.hpp mode change 100755 => 100644 bsnes/nall/dl.hpp mode change 100755 => 100644 bsnes/nall/dsp.hpp mode change 100755 => 100644 bsnes/nall/dsp/buffer.hpp mode change 100755 => 100644 bsnes/nall/dsp/core.hpp mode change 100755 => 100644 bsnes/nall/dsp/resample/average.hpp mode change 100755 => 100644 bsnes/nall/dsp/resample/cosine.hpp mode change 100755 => 100644 bsnes/nall/dsp/resample/cubic.hpp mode change 100755 => 100644 bsnes/nall/dsp/resample/hermite.hpp mode change 100755 => 100644 bsnes/nall/dsp/resample/lib/sinc.hpp mode change 100755 => 100644 bsnes/nall/dsp/resample/linear.hpp mode change 100755 => 100644 bsnes/nall/dsp/resample/nearest.hpp mode change 100755 => 100644 bsnes/nall/dsp/resample/sinc.hpp mode change 100755 => 100644 bsnes/nall/dsp/settings.hpp mode change 100755 => 100644 bsnes/nall/emulation/famicom.hpp mode change 100755 => 100644 bsnes/nall/emulation/game-boy-advance.hpp mode change 100755 => 100644 bsnes/nall/emulation/game-boy.hpp mode change 100755 => 100644 bsnes/nall/emulation/satellaview.hpp mode change 100755 => 100644 bsnes/nall/emulation/sufami-turbo.hpp mode change 100755 => 100644 bsnes/nall/emulation/super-famicom-usart.hpp mode change 100755 => 100644 bsnes/nall/emulation/super-famicom.hpp mode change 100755 => 100644 bsnes/nall/endian.hpp mode change 100755 => 100644 bsnes/nall/file.hpp mode change 100755 => 100644 bsnes/nall/filemap.hpp mode change 100755 => 100644 bsnes/nall/function.hpp mode change 100755 => 100644 bsnes/nall/gzip.hpp mode change 100755 => 100644 bsnes/nall/http.hpp mode change 100755 => 100644 bsnes/nall/image.hpp mode change 100755 => 100644 bsnes/nall/inflate.hpp mode change 100755 => 100644 bsnes/nall/input.hpp mode change 100755 => 100644 bsnes/nall/interpolation.hpp mode change 100755 => 100644 bsnes/nall/intrinsics.hpp mode change 100755 => 100644 bsnes/nall/invoke.hpp mode change 100755 => 100644 bsnes/nall/ips.hpp mode change 100755 => 100644 bsnes/nall/lzss.hpp mode change 100755 => 100644 bsnes/nall/map.hpp mode change 100755 => 100644 bsnes/nall/mosaic.hpp mode change 100755 => 100644 bsnes/nall/mosaic/bitstream.hpp mode change 100755 => 100644 bsnes/nall/mosaic/context.hpp mode change 100755 => 100644 bsnes/nall/mosaic/parser.hpp mode change 100755 => 100644 bsnes/nall/nall.hpp mode change 100755 => 100644 bsnes/nall/platform.hpp mode change 100755 => 100644 bsnes/nall/png.hpp mode change 100755 => 100644 bsnes/nall/priority-queue.hpp mode change 100755 => 100644 bsnes/nall/property.hpp mode change 100755 => 100644 bsnes/nall/public-cast.hpp mode change 100755 => 100644 bsnes/nall/random.hpp mode change 100755 => 100644 bsnes/nall/serial.hpp mode change 100755 => 100644 bsnes/nall/serializer.hpp mode change 100755 => 100644 bsnes/nall/set.hpp mode change 100755 => 100644 bsnes/nall/sha256.hpp mode change 100755 => 100644 bsnes/nall/sort.hpp mode change 100755 => 100644 bsnes/nall/stdint.hpp mode change 100755 => 100644 bsnes/nall/stream.hpp mode change 100755 => 100644 bsnes/nall/stream/auto.hpp mode change 100755 => 100644 bsnes/nall/stream/file.hpp mode change 100755 => 100644 bsnes/nall/stream/gzip.hpp mode change 100755 => 100644 bsnes/nall/stream/http.hpp mode change 100755 => 100644 bsnes/nall/stream/memory.hpp mode change 100755 => 100644 bsnes/nall/stream/mmap.hpp mode change 100755 => 100644 bsnes/nall/stream/stream.hpp mode change 100755 => 100644 bsnes/nall/stream/vector.hpp mode change 100755 => 100644 bsnes/nall/stream/zip.hpp mode change 100755 => 100644 bsnes/nall/string.hpp mode change 100755 => 100644 bsnes/nall/string/base.hpp mode change 100755 => 100644 bsnes/nall/string/bml.hpp mode change 100755 => 100644 bsnes/nall/string/bsv.hpp mode change 100755 => 100644 bsnes/nall/string/cast.hpp mode change 100755 => 100644 bsnes/nall/string/compare.hpp mode change 100755 => 100644 bsnes/nall/string/convert.hpp mode change 100755 => 100644 bsnes/nall/string/core.hpp mode change 100755 => 100644 bsnes/nall/string/cstring.hpp mode change 100755 => 100644 bsnes/nall/string/filename.hpp mode change 100755 => 100644 bsnes/nall/string/math-fixed-point.hpp mode change 100755 => 100644 bsnes/nall/string/math-floating-point.hpp mode change 100755 => 100644 bsnes/nall/string/platform.hpp mode change 100755 => 100644 bsnes/nall/string/replace.hpp mode change 100755 => 100644 bsnes/nall/string/split.hpp mode change 100755 => 100644 bsnes/nall/string/static.hpp mode change 100755 => 100644 bsnes/nall/string/strm.hpp mode change 100755 => 100644 bsnes/nall/string/strpos.hpp mode change 100755 => 100644 bsnes/nall/string/trim.hpp mode change 100755 => 100644 bsnes/nall/string/utf8.hpp mode change 100755 => 100644 bsnes/nall/string/utility.hpp mode change 100755 => 100644 bsnes/nall/string/variadic.hpp mode change 100755 => 100644 bsnes/nall/string/wildcard.hpp mode change 100755 => 100644 bsnes/nall/string/wrapper.hpp mode change 100755 => 100644 bsnes/nall/string/xml-legacy.hpp mode change 100755 => 100644 bsnes/nall/string/xml.hpp mode change 100755 => 100644 bsnes/nall/traits.hpp mode change 100755 => 100644 bsnes/nall/udl.hpp mode change 100755 => 100644 bsnes/nall/ups.hpp mode change 100755 => 100644 bsnes/nall/utility.hpp mode change 100755 => 100644 bsnes/nall/varint.hpp mode change 100755 => 100644 bsnes/nall/vector.hpp mode change 100755 => 100644 bsnes/nall/windows/detour.hpp mode change 100755 => 100644 bsnes/nall/windows/guid.hpp mode change 100755 => 100644 bsnes/nall/windows/launcher.hpp mode change 100755 => 100644 bsnes/nall/windows/registry.hpp mode change 100755 => 100644 bsnes/nall/windows/utf8.hpp mode change 100755 => 100644 bsnes/nall/xorg/guard.hpp mode change 100755 => 100644 bsnes/nall/xorg/xorg.hpp mode change 100755 => 100644 bsnes/nall/zip.hpp create mode 100644 bsnes/nds/Makefile create mode 100644 bsnes/nds/apu/apu.cpp create mode 100644 bsnes/nds/apu/apu.hpp create mode 100644 bsnes/nds/cpu/arm.cpp create mode 100644 bsnes/nds/cpu/arm7tdmi.cpp create mode 100644 bsnes/nds/cpu/arm946es.cpp create mode 100644 bsnes/nds/cpu/bit.hpp create mode 100644 bsnes/nds/cpu/core.cpp create mode 100644 bsnes/nds/cpu/core.hpp create mode 100644 bsnes/nds/cpu/cpu.cpp create mode 100644 bsnes/nds/cpu/cpu.hpp create mode 100644 bsnes/nds/cpu/disasm.cpp create mode 100644 bsnes/nds/cpu/dma.cpp create mode 100644 bsnes/nds/cpu/math.cpp create mode 100644 bsnes/nds/cpu/message.cpp create mode 100644 bsnes/nds/cpu/slot.cpp create mode 100644 bsnes/nds/cpu/thumb.cpp create mode 100644 bsnes/nds/cpu/timer.cpp create mode 100644 bsnes/nds/gpu/commands.cpp create mode 100644 bsnes/nds/gpu/commands.hpp create mode 100644 bsnes/nds/gpu/geometry.cpp create mode 100644 bsnes/nds/gpu/geometry.hpp create mode 100644 bsnes/nds/gpu/gpu.cpp create mode 100644 bsnes/nds/gpu/gpu.hpp create mode 100644 bsnes/nds/gpu/math.cpp create mode 100644 bsnes/nds/gpu/math.hpp create mode 100644 bsnes/nds/gpu/render.cpp create mode 100644 bsnes/nds/gpu/render.hpp create mode 100644 bsnes/nds/gpu/textures.cpp create mode 100644 bsnes/nds/interface/interface.cpp create mode 100644 bsnes/nds/interface/interface.hpp create mode 100644 bsnes/nds/memory/eeprom.cpp create mode 100644 bsnes/nds/memory/eeprom.hpp create mode 100644 bsnes/nds/memory/flash.cpp create mode 100644 bsnes/nds/memory/flash.hpp create mode 100644 bsnes/nds/memory/fram.cpp create mode 100644 bsnes/nds/memory/fram.hpp create mode 100644 bsnes/nds/memory/memory.cpp create mode 100644 bsnes/nds/memory/memory.hpp create mode 100644 bsnes/nds/nds.hpp create mode 100644 bsnes/nds/ppu/bg.cpp create mode 100644 bsnes/nds/ppu/obj.cpp create mode 100644 bsnes/nds/ppu/ppu.cpp create mode 100644 bsnes/nds/ppu/ppu.hpp create mode 100644 bsnes/nds/slot1/slot1.cpp create mode 100644 bsnes/nds/slot1/slot1.hpp create mode 100644 bsnes/nds/slot2/slot2.cpp create mode 100644 bsnes/nds/slot2/slot2.hpp create mode 100644 bsnes/nds/system/clock.cpp create mode 100644 bsnes/nds/system/eventqueue.hpp create mode 100644 bsnes/nds/system/powermgr.cpp create mode 100644 bsnes/nds/system/system.cpp create mode 100644 bsnes/nds/system/system.hpp create mode 100644 bsnes/nds/system/touchscreen.cpp create mode 100644 bsnes/nds/video/video.cpp create mode 100644 bsnes/nds/video/video.hpp create mode 100644 bsnes/nds/wifi/wifi.cpp create mode 100644 bsnes/nds/wifi/wifi.hpp mode change 100755 => 100644 bsnes/phoenix/Makefile mode change 100755 => 100644 bsnes/phoenix/core/core.cpp mode change 100755 => 100644 bsnes/phoenix/core/core.hpp mode change 100755 => 100644 bsnes/phoenix/core/keyboard.hpp mode change 100755 => 100644 bsnes/phoenix/core/layout/fixed-layout.cpp mode change 100755 => 100644 bsnes/phoenix/core/layout/fixed-layout.hpp mode change 100755 => 100644 bsnes/phoenix/core/layout/horizontal-layout.cpp mode change 100755 => 100644 bsnes/phoenix/core/layout/horizontal-layout.hpp mode change 100755 => 100644 bsnes/phoenix/core/layout/vertical-layout.cpp mode change 100755 => 100644 bsnes/phoenix/core/layout/vertical-layout.hpp mode change 100755 => 100644 bsnes/phoenix/core/state.hpp mode change 100755 => 100644 bsnes/phoenix/gtk/action/action.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/action/check-item.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/action/item.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/action/menu.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/action/radio-item.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/action/separator.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/desktop.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/dialog-window.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/font.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/keyboard.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/message-window.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/mouse.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/platform.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/platform.hpp mode change 100755 => 100644 bsnes/phoenix/gtk/settings.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/timer.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/utility.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/button.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/canvas.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/check-box.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/combo-box.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/hex-edit.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/horizontal-scroll-bar.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/horizontal-slider.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/label.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/line-edit.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/list-view.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/progress-bar.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/radio-box.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/text-edit.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/vertical-scroll-bar.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/vertical-slider.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/viewport.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/widget/widget.cpp mode change 100755 => 100644 bsnes/phoenix/gtk/window.cpp mode change 100755 => 100644 bsnes/phoenix/phoenix.cpp mode change 100755 => 100644 bsnes/phoenix/phoenix.hpp mode change 100755 => 100644 bsnes/phoenix/qt/action/action.cpp mode change 100755 => 100644 bsnes/phoenix/qt/action/check-item.cpp mode change 100755 => 100644 bsnes/phoenix/qt/action/item.cpp mode change 100755 => 100644 bsnes/phoenix/qt/action/menu.cpp mode change 100755 => 100644 bsnes/phoenix/qt/action/radio-item.cpp mode change 100755 => 100644 bsnes/phoenix/qt/action/separator.cpp mode change 100755 => 100644 bsnes/phoenix/qt/desktop.cpp mode change 100755 => 100644 bsnes/phoenix/qt/dialog-window.cpp mode change 100755 => 100644 bsnes/phoenix/qt/font.cpp mode change 100755 => 100644 bsnes/phoenix/qt/keyboard.cpp mode change 100755 => 100644 bsnes/phoenix/qt/message-window.cpp mode change 100755 => 100644 bsnes/phoenix/qt/mouse.cpp mode change 100755 => 100644 bsnes/phoenix/qt/platform.cpp mode change 100755 => 100644 bsnes/phoenix/qt/platform.moc mode change 100755 => 100644 bsnes/phoenix/qt/platform.moc.hpp mode change 100755 => 100644 bsnes/phoenix/qt/settings.cpp mode change 100755 => 100644 bsnes/phoenix/qt/timer.cpp mode change 100755 => 100644 bsnes/phoenix/qt/utility.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/button.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/canvas.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/check-box.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/combo-box.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/hex-edit.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/horizontal-scroll-bar.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/horizontal-slider.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/label.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/line-edit.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/list-view.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/progress-bar.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/radio-box.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/text-edit.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/vertical-scroll-bar.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/vertical-slider.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/viewport.cpp mode change 100755 => 100644 bsnes/phoenix/qt/widget/widget.cpp mode change 100755 => 100644 bsnes/phoenix/qt/window.cpp mode change 100755 => 100644 bsnes/phoenix/reference/action/action.cpp mode change 100755 => 100644 bsnes/phoenix/reference/action/check-item.cpp mode change 100755 => 100644 bsnes/phoenix/reference/action/item.cpp mode change 100755 => 100644 bsnes/phoenix/reference/action/menu.cpp mode change 100755 => 100644 bsnes/phoenix/reference/action/radio-item.cpp mode change 100755 => 100644 bsnes/phoenix/reference/action/separator.cpp mode change 100755 => 100644 bsnes/phoenix/reference/desktop.cpp mode change 100755 => 100644 bsnes/phoenix/reference/dialog-window.cpp mode change 100755 => 100644 bsnes/phoenix/reference/font.cpp mode change 100755 => 100644 bsnes/phoenix/reference/keyboard.cpp mode change 100755 => 100644 bsnes/phoenix/reference/message-window.cpp mode change 100755 => 100644 bsnes/phoenix/reference/mouse.cpp mode change 100755 => 100644 bsnes/phoenix/reference/platform.cpp mode change 100755 => 100644 bsnes/phoenix/reference/platform.hpp mode change 100755 => 100644 bsnes/phoenix/reference/timer.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/button.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/canvas.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/check-box.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/combo-box.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/hex-edit.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/horizontal-scroll-bar.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/horizontal-slider.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/label.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/line-edit.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/list-view.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/progress-bar.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/radio-box.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/text-edit.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/vertical-scroll-bar.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/vertical-slider.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/viewport.cpp mode change 100755 => 100644 bsnes/phoenix/reference/widget/widget.cpp mode change 100755 => 100644 bsnes/phoenix/reference/window.cpp mode change 100755 => 100644 bsnes/phoenix/sync.sh mode change 100755 => 100644 bsnes/phoenix/windows/action/action.cpp mode change 100755 => 100644 bsnes/phoenix/windows/action/check-item.cpp mode change 100755 => 100644 bsnes/phoenix/windows/action/item.cpp mode change 100755 => 100644 bsnes/phoenix/windows/action/menu.cpp mode change 100755 => 100644 bsnes/phoenix/windows/action/radio-item.cpp mode change 100755 => 100644 bsnes/phoenix/windows/action/separator.cpp mode change 100755 => 100644 bsnes/phoenix/windows/desktop.cpp mode change 100755 => 100644 bsnes/phoenix/windows/dialog-window.cpp mode change 100755 => 100644 bsnes/phoenix/windows/font.cpp mode change 100755 => 100644 bsnes/phoenix/windows/keyboard.cpp mode change 100755 => 100644 bsnes/phoenix/windows/message-window.cpp mode change 100755 => 100644 bsnes/phoenix/windows/mouse.cpp mode change 100755 => 100644 bsnes/phoenix/windows/object.cpp mode change 100755 => 100644 bsnes/phoenix/windows/phoenix.Manifest mode change 100755 => 100644 bsnes/phoenix/windows/phoenix.rc mode change 100755 => 100644 bsnes/phoenix/windows/platform.cpp mode change 100755 => 100644 bsnes/phoenix/windows/platform.hpp mode change 100755 => 100644 bsnes/phoenix/windows/settings.cpp mode change 100755 => 100644 bsnes/phoenix/windows/timer.cpp mode change 100755 => 100644 bsnes/phoenix/windows/utility.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/button.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/canvas.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/check-box.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/combo-box.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/hex-edit.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/horizontal-scroll-bar.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/horizontal-slider.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/label.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/line-edit.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/list-view.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/progress-bar.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/radio-box.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/text-edit.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/vertical-scroll-bar.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/vertical-slider.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/viewport.cpp mode change 100755 => 100644 bsnes/phoenix/windows/widget/widget.cpp mode change 100755 => 100644 bsnes/phoenix/windows/window.cpp mode change 100755 => 100644 bsnes/processor/Makefile mode change 100755 => 100644 bsnes/processor/arm/algorithms.cpp mode change 100755 => 100644 bsnes/processor/arm/arm.cpp mode change 100755 => 100644 bsnes/processor/arm/arm.hpp mode change 100755 => 100644 bsnes/processor/arm/disassembler.cpp mode change 100755 => 100644 bsnes/processor/arm/disassembler.hpp mode change 100755 => 100644 bsnes/processor/arm/instructions-arm.cpp mode change 100755 => 100644 bsnes/processor/arm/instructions-arm.hpp mode change 100755 => 100644 bsnes/processor/arm/instructions-thumb.cpp mode change 100755 => 100644 bsnes/processor/arm/instructions-thumb.hpp mode change 100755 => 100644 bsnes/processor/arm/registers.cpp mode change 100755 => 100644 bsnes/processor/arm/registers.hpp mode change 100755 => 100644 bsnes/processor/arm/serialization.cpp mode change 100755 => 100644 bsnes/processor/gsu/gsu.cpp mode change 100755 => 100644 bsnes/processor/gsu/gsu.hpp mode change 100755 => 100644 bsnes/processor/gsu/instructions.cpp mode change 100755 => 100644 bsnes/processor/gsu/registers.hpp mode change 100755 => 100644 bsnes/processor/gsu/serialization.cpp mode change 100755 => 100644 bsnes/processor/gsu/table.cpp mode change 100755 => 100644 bsnes/processor/hg51b/hg51b.cpp mode change 100755 => 100644 bsnes/processor/hg51b/hg51b.hpp mode change 100755 => 100644 bsnes/processor/hg51b/instructions.cpp mode change 100755 => 100644 bsnes/processor/hg51b/registers.cpp mode change 100755 => 100644 bsnes/processor/hg51b/registers.hpp mode change 100755 => 100644 bsnes/processor/hg51b/serialization.cpp mode change 100755 => 100644 bsnes/processor/lr35902/disassembler.cpp mode change 100755 => 100644 bsnes/processor/lr35902/instructions.cpp mode change 100755 => 100644 bsnes/processor/lr35902/lr35902.cpp mode change 100755 => 100644 bsnes/processor/lr35902/lr35902.hpp mode change 100755 => 100644 bsnes/processor/lr35902/registers.hpp mode change 100755 => 100644 bsnes/processor/lr35902/serialization.cpp mode change 100755 => 100644 bsnes/processor/processor.hpp mode change 100755 => 100644 bsnes/processor/r6502/disassembler.cpp mode change 100755 => 100644 bsnes/processor/r6502/instructions.cpp mode change 100755 => 100644 bsnes/processor/r6502/memory.cpp mode change 100755 => 100644 bsnes/processor/r6502/r6502.cpp mode change 100755 => 100644 bsnes/processor/r6502/r6502.hpp mode change 100755 => 100644 bsnes/processor/r6502/registers.hpp mode change 100755 => 100644 bsnes/processor/r6502/serialization.cpp mode change 100755 => 100644 bsnes/processor/r65816/algorithms.cpp mode change 100755 => 100644 bsnes/processor/r65816/disassembler.cpp mode change 100755 => 100644 bsnes/processor/r65816/disassembler.hpp mode change 100755 => 100644 bsnes/processor/r65816/memory.hpp mode change 100755 => 100644 bsnes/processor/r65816/opcode_misc.cpp mode change 100755 => 100644 bsnes/processor/r65816/opcode_pc.cpp mode change 100755 => 100644 bsnes/processor/r65816/opcode_read.cpp mode change 100755 => 100644 bsnes/processor/r65816/opcode_rmw.cpp mode change 100755 => 100644 bsnes/processor/r65816/opcode_write.cpp mode change 100755 => 100644 bsnes/processor/r65816/r65816.cpp mode change 100755 => 100644 bsnes/processor/r65816/r65816.hpp mode change 100755 => 100644 bsnes/processor/r65816/registers.hpp mode change 100755 => 100644 bsnes/processor/r65816/serialization.cpp mode change 100755 => 100644 bsnes/processor/r65816/table.cpp mode change 100755 => 100644 bsnes/processor/spc700/algorithms.cpp mode change 100755 => 100644 bsnes/processor/spc700/disassembler.cpp mode change 100755 => 100644 bsnes/processor/spc700/instructions.cpp mode change 100755 => 100644 bsnes/processor/spc700/memory.hpp mode change 100755 => 100644 bsnes/processor/spc700/registers.hpp mode change 100755 => 100644 bsnes/processor/spc700/serialization.cpp mode change 100755 => 100644 bsnes/processor/spc700/spc700.cpp mode change 100755 => 100644 bsnes/processor/spc700/spc700.hpp mode change 100755 => 100644 bsnes/processor/upd96050/disassembler.cpp mode change 100755 => 100644 bsnes/processor/upd96050/instructions.cpp mode change 100755 => 100644 bsnes/processor/upd96050/memory.cpp mode change 100755 => 100644 bsnes/processor/upd96050/registers.hpp mode change 100755 => 100644 bsnes/processor/upd96050/serialization.cpp mode change 100755 => 100644 bsnes/processor/upd96050/upd96050.cpp mode change 100755 => 100644 bsnes/processor/upd96050/upd96050.hpp mode change 100755 => 100644 bsnes/profile/BS-X Satellaview.sfc/manifest.xml mode change 100755 => 100644 bsnes/profile/Famicom.sys/manifest.xml mode change 100755 => 100644 bsnes/profile/Game Boy Advance.sys/manifest.xml mode change 100755 => 100644 bsnes/profile/Game Boy Color.sys/boot.rom mode change 100755 => 100644 bsnes/profile/Game Boy Color.sys/manifest.xml mode change 100755 => 100644 bsnes/profile/Game Boy.sys/boot.rom mode change 100755 => 100644 bsnes/profile/Game Boy.sys/manifest.xml create mode 100644 bsnes/profile/Nintendo DS.sys/manifest.xml mode change 100755 => 100644 bsnes/profile/Sufami Turbo.sfc/manifest.xml mode change 100755 => 100644 bsnes/profile/Super Famicom.sys/manifest.xml mode change 100755 => 100644 bsnes/profile/Super Famicom.sys/spc700.rom mode change 100755 => 100644 bsnes/profile/Super Game Boy.sfc/boot.rom mode change 100755 => 100644 bsnes/profile/Super Game Boy.sfc/manifest.xml mode change 100755 => 100644 bsnes/ruby/Makefile mode change 100755 => 100644 bsnes/ruby/audio.hpp mode change 100755 => 100644 bsnes/ruby/audio/alsa.cpp mode change 100755 => 100644 bsnes/ruby/audio/ao.cpp mode change 100755 => 100644 bsnes/ruby/audio/directsound.cpp mode change 100755 => 100644 bsnes/ruby/audio/openal.cpp mode change 100755 => 100644 bsnes/ruby/audio/oss.cpp mode change 100755 => 100644 bsnes/ruby/audio/pulseaudio.cpp mode change 100755 => 100644 bsnes/ruby/audio/pulseaudiosimple.cpp mode change 100755 => 100644 bsnes/ruby/audio/xaudio2.cpp mode change 100755 => 100644 bsnes/ruby/audio/xaudio2.hpp mode change 100755 => 100644 bsnes/ruby/input.hpp mode change 100755 => 100644 bsnes/ruby/input/carbon.cpp mode change 100755 => 100644 bsnes/ruby/input/directinput.cpp mode change 100755 => 100644 bsnes/ruby/input/rawinput.cpp mode change 100755 => 100644 bsnes/ruby/input/sdl.cpp mode change 100755 => 100644 bsnes/ruby/input/x.cpp mode change 100755 => 100644 bsnes/ruby/input/xlibkeys.hpp mode change 100755 => 100644 bsnes/ruby/ruby.cpp mode change 100755 => 100644 bsnes/ruby/ruby.hpp mode change 100755 => 100644 bsnes/ruby/ruby_impl.cpp mode change 100755 => 100644 bsnes/ruby/video.hpp mode change 100755 => 100644 bsnes/ruby/video/direct3d.cpp mode change 100755 => 100644 bsnes/ruby/video/directdraw.cpp mode change 100755 => 100644 bsnes/ruby/video/gdi.cpp mode change 100755 => 100644 bsnes/ruby/video/glx.cpp mode change 100755 => 100644 bsnes/ruby/video/opengl.hpp mode change 100755 => 100644 bsnes/ruby/video/qtopengl.cpp mode change 100755 => 100644 bsnes/ruby/video/qtraster.cpp mode change 100755 => 100644 bsnes/ruby/video/sdl.cpp mode change 100755 => 100644 bsnes/ruby/video/wgl.cpp mode change 100755 => 100644 bsnes/ruby/video/xshm.cpp mode change 100755 => 100644 bsnes/ruby/video/xv.cpp mode change 100755 => 100644 bsnes/sfc/Makefile mode change 100755 => 100644 bsnes/sfc/alt/cpu/cpu.cpp mode change 100755 => 100644 bsnes/sfc/alt/cpu/cpu.hpp mode change 100755 => 100644 bsnes/sfc/alt/cpu/dma.cpp mode change 100755 => 100644 bsnes/sfc/alt/cpu/memory.cpp mode change 100755 => 100644 bsnes/sfc/alt/cpu/mmio.cpp mode change 100755 => 100644 bsnes/sfc/alt/cpu/serialization.cpp mode change 100755 => 100644 bsnes/sfc/alt/cpu/timing.cpp mode change 100755 => 100644 bsnes/sfc/alt/dsp/SPC_DSP.cpp mode change 100755 => 100644 bsnes/sfc/alt/dsp/SPC_DSP.h mode change 100755 => 100644 bsnes/sfc/alt/dsp/blargg_common.h mode change 100755 => 100644 bsnes/sfc/alt/dsp/blargg_config.h mode change 100755 => 100644 bsnes/sfc/alt/dsp/blargg_endian.h mode change 100755 => 100644 bsnes/sfc/alt/dsp/blargg_source.h mode change 100755 => 100644 bsnes/sfc/alt/dsp/dsp.cpp mode change 100755 => 100644 bsnes/sfc/alt/dsp/dsp.hpp mode change 100755 => 100644 bsnes/sfc/alt/dsp/serialization.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/memory/memory.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/memory/memory.hpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/mmio/mmio.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/mmio/mmio.hpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/ppu.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/ppu.hpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/render/addsub.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/render/bg.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/render/cache.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/render/line.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/render/mode7.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/render/oam.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/render/render.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/render/render.hpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/render/windows.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-compatibility/serialization.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/background/background.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/background/background.hpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/background/mode7.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/cache/cache.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/cache/cache.hpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/mmio/mmio.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/mmio/mmio.hpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/ppu.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/ppu.hpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/screen/screen.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/screen/screen.hpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/serialization.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/sprite/sprite.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/sprite/sprite.hpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/window/window.cpp mode change 100755 => 100644 bsnes/sfc/alt/ppu-performance/window/window.hpp mode change 100755 => 100644 bsnes/sfc/alt/smp/algorithms.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core/cc.sh mode change 100755 => 100644 bsnes/sfc/alt/smp/core/generate.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core/op_misc.b mode change 100755 => 100644 bsnes/sfc/alt/smp/core/op_misc.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core/op_mov.b mode change 100755 => 100644 bsnes/sfc/alt/smp/core/op_mov.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core/op_pc.b mode change 100755 => 100644 bsnes/sfc/alt/smp/core/op_pc.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core/op_read.b mode change 100755 => 100644 bsnes/sfc/alt/smp/core/op_read.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core/op_rmw.b mode change 100755 => 100644 bsnes/sfc/alt/smp/core/op_rmw.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core/opcycle_misc.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core/opcycle_mov.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core/opcycle_pc.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core/opcycle_read.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/core/opcycle_rmw.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/disassembler.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/memory.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/smp.cpp mode change 100755 => 100644 bsnes/sfc/alt/smp/smp.hpp mode change 100755 => 100644 bsnes/sfc/alt/smp/timing.cpp mode change 100755 => 100644 bsnes/sfc/cartridge/cartridge.cpp mode change 100755 => 100644 bsnes/sfc/cartridge/cartridge.hpp mode change 100755 => 100644 bsnes/sfc/cartridge/markup.cpp mode change 100755 => 100644 bsnes/sfc/cartridge/serialization.cpp mode change 100755 => 100644 bsnes/sfc/cheat/cheat.cpp mode change 100755 => 100644 bsnes/sfc/cheat/cheat.hpp mode change 100755 => 100644 bsnes/sfc/chip/armdsp/armdsp.cpp mode change 100755 => 100644 bsnes/sfc/chip/armdsp/armdsp.hpp mode change 100755 => 100644 bsnes/sfc/chip/armdsp/memory.cpp mode change 100755 => 100644 bsnes/sfc/chip/armdsp/registers.hpp mode change 100755 => 100644 bsnes/sfc/chip/armdsp/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/bsx/bsx.cpp mode change 100755 => 100644 bsnes/sfc/chip/bsx/bsx.hpp mode change 100755 => 100644 bsnes/sfc/chip/bsx/cartridge/cartridge.cpp mode change 100755 => 100644 bsnes/sfc/chip/bsx/cartridge/cartridge.hpp mode change 100755 => 100644 bsnes/sfc/chip/bsx/cartridge/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/bsx/flash/flash.cpp mode change 100755 => 100644 bsnes/sfc/chip/bsx/flash/flash.hpp mode change 100755 => 100644 bsnes/sfc/chip/bsx/satellaview/satellaview.cpp mode change 100755 => 100644 bsnes/sfc/chip/bsx/satellaview/satellaview.hpp mode change 100755 => 100644 bsnes/sfc/chip/chip.hpp mode change 100755 => 100644 bsnes/sfc/chip/epsonrtc/epsonrtc.cpp mode change 100755 => 100644 bsnes/sfc/chip/epsonrtc/epsonrtc.hpp mode change 100755 => 100644 bsnes/sfc/chip/epsonrtc/memory.cpp mode change 100755 => 100644 bsnes/sfc/chip/epsonrtc/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/epsonrtc/time.cpp mode change 100755 => 100644 bsnes/sfc/chip/hitachidsp/hitachidsp.cpp mode change 100755 => 100644 bsnes/sfc/chip/hitachidsp/hitachidsp.hpp mode change 100755 => 100644 bsnes/sfc/chip/hitachidsp/memory.cpp mode change 100755 => 100644 bsnes/sfc/chip/hitachidsp/mmio.hpp mode change 100755 => 100644 bsnes/sfc/chip/hitachidsp/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/icd2/icd2.cpp mode change 100755 => 100644 bsnes/sfc/chip/icd2/icd2.hpp mode change 100755 => 100644 bsnes/sfc/chip/icd2/interface/interface.cpp mode change 100755 => 100644 bsnes/sfc/chip/icd2/interface/interface.hpp mode change 100755 => 100644 bsnes/sfc/chip/icd2/mmio/mmio.cpp mode change 100755 => 100644 bsnes/sfc/chip/icd2/mmio/mmio.hpp mode change 100755 => 100644 bsnes/sfc/chip/icd2/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/msu1/msu1.cpp mode change 100755 => 100644 bsnes/sfc/chip/msu1/msu1.hpp mode change 100755 => 100644 bsnes/sfc/chip/msu1/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/necdsp/necdsp.cpp mode change 100755 => 100644 bsnes/sfc/chip/necdsp/necdsp.hpp mode change 100755 => 100644 bsnes/sfc/chip/necdsp/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/nss/nss.cpp mode change 100755 => 100644 bsnes/sfc/chip/nss/nss.hpp mode change 100755 => 100644 bsnes/sfc/chip/obc1/obc1.cpp mode change 100755 => 100644 bsnes/sfc/chip/obc1/obc1.hpp mode change 100755 => 100644 bsnes/sfc/chip/obc1/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/sa1/bus/bus.cpp mode change 100755 => 100644 bsnes/sfc/chip/sa1/bus/bus.hpp mode change 100755 => 100644 bsnes/sfc/chip/sa1/dma/dma.cpp mode change 100755 => 100644 bsnes/sfc/chip/sa1/dma/dma.hpp mode change 100755 => 100644 bsnes/sfc/chip/sa1/memory/memory.cpp mode change 100755 => 100644 bsnes/sfc/chip/sa1/memory/memory.hpp mode change 100755 => 100644 bsnes/sfc/chip/sa1/mmio/mmio.cpp mode change 100755 => 100644 bsnes/sfc/chip/sa1/mmio/mmio.hpp mode change 100755 => 100644 bsnes/sfc/chip/sa1/sa1.cpp mode change 100755 => 100644 bsnes/sfc/chip/sa1/sa1.hpp mode change 100755 => 100644 bsnes/sfc/chip/sa1/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/sdd1/decomp.cpp mode change 100755 => 100644 bsnes/sfc/chip/sdd1/decomp.hpp mode change 100755 => 100644 bsnes/sfc/chip/sdd1/sdd1.cpp mode change 100755 => 100644 bsnes/sfc/chip/sdd1/sdd1.hpp mode change 100755 => 100644 bsnes/sfc/chip/sdd1/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/sharprtc/memory.cpp mode change 100755 => 100644 bsnes/sfc/chip/sharprtc/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/sharprtc/sharprtc.cpp mode change 100755 => 100644 bsnes/sfc/chip/sharprtc/sharprtc.hpp mode change 100755 => 100644 bsnes/sfc/chip/sharprtc/time.cpp mode change 100755 => 100644 bsnes/sfc/chip/spc7110/alu.cpp mode change 100755 => 100644 bsnes/sfc/chip/spc7110/data.cpp mode change 100755 => 100644 bsnes/sfc/chip/spc7110/dcu.cpp mode change 100755 => 100644 bsnes/sfc/chip/spc7110/decompressor.cpp mode change 100755 => 100644 bsnes/sfc/chip/spc7110/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/spc7110/spc7110.cpp mode change 100755 => 100644 bsnes/sfc/chip/spc7110/spc7110.hpp mode change 100755 => 100644 bsnes/sfc/chip/sufamiturbo/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/sufamiturbo/sufamiturbo.cpp mode change 100755 => 100644 bsnes/sfc/chip/sufamiturbo/sufamiturbo.hpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/bus/bus.cpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/bus/bus.hpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/core/core.cpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/core/core.hpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/disasm/disasm.cpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/disasm/disasm.hpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/memory/memory.cpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/memory/memory.hpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/mmio/mmio.cpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/mmio/mmio.hpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/serialization.cpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/superfx.cpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/superfx.hpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/timing/timing.cpp mode change 100755 => 100644 bsnes/sfc/chip/superfx/timing/timing.hpp mode change 100755 => 100644 bsnes/sfc/config/config.cpp mode change 100755 => 100644 bsnes/sfc/config/config.hpp mode change 100755 => 100644 bsnes/sfc/controller/controller.cpp mode change 100755 => 100644 bsnes/sfc/controller/controller.hpp mode change 100755 => 100644 bsnes/sfc/controller/gamepad/gamepad.cpp mode change 100755 => 100644 bsnes/sfc/controller/gamepad/gamepad.hpp mode change 100755 => 100644 bsnes/sfc/controller/justifier/justifier.cpp mode change 100755 => 100644 bsnes/sfc/controller/justifier/justifier.hpp mode change 100755 => 100644 bsnes/sfc/controller/mouse/mouse.cpp mode change 100755 => 100644 bsnes/sfc/controller/mouse/mouse.hpp mode change 100755 => 100644 bsnes/sfc/controller/multitap/multitap.cpp mode change 100755 => 100644 bsnes/sfc/controller/multitap/multitap.hpp mode change 100755 => 100644 bsnes/sfc/controller/superscope/superscope.cpp mode change 100755 => 100644 bsnes/sfc/controller/superscope/superscope.hpp mode change 100755 => 100644 bsnes/sfc/controller/usart/usart.cpp mode change 100755 => 100644 bsnes/sfc/controller/usart/usart.hpp mode change 100755 => 100644 bsnes/sfc/cpu/cpu.cpp mode change 100755 => 100644 bsnes/sfc/cpu/cpu.hpp mode change 100755 => 100644 bsnes/sfc/cpu/dma/dma.cpp mode change 100755 => 100644 bsnes/sfc/cpu/dma/dma.hpp mode change 100755 => 100644 bsnes/sfc/cpu/memory/memory.cpp mode change 100755 => 100644 bsnes/sfc/cpu/memory/memory.hpp mode change 100755 => 100644 bsnes/sfc/cpu/mmio/mmio.cpp mode change 100755 => 100644 bsnes/sfc/cpu/mmio/mmio.hpp mode change 100755 => 100644 bsnes/sfc/cpu/serialization.cpp mode change 100755 => 100644 bsnes/sfc/cpu/timing/irq.cpp mode change 100755 => 100644 bsnes/sfc/cpu/timing/joypad.cpp mode change 100755 => 100644 bsnes/sfc/cpu/timing/timing.cpp mode change 100755 => 100644 bsnes/sfc/cpu/timing/timing.hpp mode change 100755 => 100644 bsnes/sfc/dsp/brr.cpp mode change 100755 => 100644 bsnes/sfc/dsp/counter.cpp mode change 100755 => 100644 bsnes/sfc/dsp/dsp.cpp mode change 100755 => 100644 bsnes/sfc/dsp/dsp.hpp mode change 100755 => 100644 bsnes/sfc/dsp/echo.cpp mode change 100755 => 100644 bsnes/sfc/dsp/envelope.cpp mode change 100755 => 100644 bsnes/sfc/dsp/gaussian.cpp mode change 100755 => 100644 bsnes/sfc/dsp/misc.cpp mode change 100755 => 100644 bsnes/sfc/dsp/moduloarray.hpp mode change 100755 => 100644 bsnes/sfc/dsp/serialization.cpp mode change 100755 => 100644 bsnes/sfc/dsp/voice.cpp mode change 100755 => 100644 bsnes/sfc/interface/interface.cpp mode change 100755 => 100644 bsnes/sfc/interface/interface.hpp mode change 100755 => 100644 bsnes/sfc/memory/memory-inline.hpp mode change 100755 => 100644 bsnes/sfc/memory/memory.cpp mode change 100755 => 100644 bsnes/sfc/memory/memory.hpp mode change 100755 => 100644 bsnes/sfc/ppu/background/background.cpp mode change 100755 => 100644 bsnes/sfc/ppu/background/background.hpp mode change 100755 => 100644 bsnes/sfc/ppu/background/mode7.cpp mode change 100755 => 100644 bsnes/sfc/ppu/counter/counter-inline.hpp mode change 100755 => 100644 bsnes/sfc/ppu/counter/counter.hpp mode change 100755 => 100644 bsnes/sfc/ppu/mmio/mmio.cpp mode change 100755 => 100644 bsnes/sfc/ppu/mmio/mmio.hpp mode change 100755 => 100644 bsnes/sfc/ppu/ppu.cpp mode change 100755 => 100644 bsnes/sfc/ppu/ppu.hpp mode change 100755 => 100644 bsnes/sfc/ppu/screen/screen.cpp mode change 100755 => 100644 bsnes/sfc/ppu/screen/screen.hpp mode change 100755 => 100644 bsnes/sfc/ppu/serialization.cpp mode change 100755 => 100644 bsnes/sfc/ppu/sprite/list.cpp mode change 100755 => 100644 bsnes/sfc/ppu/sprite/sprite.cpp mode change 100755 => 100644 bsnes/sfc/ppu/sprite/sprite.hpp mode change 100755 => 100644 bsnes/sfc/ppu/window/window.cpp mode change 100755 => 100644 bsnes/sfc/ppu/window/window.hpp mode change 100755 => 100644 bsnes/sfc/profile-accuracy.hpp mode change 100755 => 100644 bsnes/sfc/profile-compatibility.hpp mode change 100755 => 100644 bsnes/sfc/profile-performance.hpp mode change 100755 => 100644 bsnes/sfc/random/random.cpp mode change 100755 => 100644 bsnes/sfc/random/random.hpp mode change 100755 => 100644 bsnes/sfc/scheduler/scheduler.cpp mode change 100755 => 100644 bsnes/sfc/scheduler/scheduler.hpp mode change 100755 => 100644 bsnes/sfc/sfc.hpp mode change 100755 => 100644 bsnes/sfc/smp/memory.cpp mode change 100755 => 100644 bsnes/sfc/smp/serialization.cpp mode change 100755 => 100644 bsnes/sfc/smp/smp.cpp mode change 100755 => 100644 bsnes/sfc/smp/smp.hpp mode change 100755 => 100644 bsnes/sfc/smp/timing.cpp mode change 100755 => 100644 bsnes/sfc/system/audio.cpp mode change 100755 => 100644 bsnes/sfc/system/audio.hpp mode change 100755 => 100644 bsnes/sfc/system/input.cpp mode change 100755 => 100644 bsnes/sfc/system/input.hpp mode change 100755 => 100644 bsnes/sfc/system/serialization.cpp mode change 100755 => 100644 bsnes/sfc/system/system.cpp mode change 100755 => 100644 bsnes/sfc/system/system.hpp mode change 100755 => 100644 bsnes/sfc/system/video.cpp mode change 100755 => 100644 bsnes/sfc/system/video.hpp mode change 100755 => 100644 bsnes/target-ethos/Makefile mode change 100755 => 100644 bsnes/target-ethos/bootstrap.cpp mode change 100755 => 100644 bsnes/target-ethos/configuration/configuration.cpp mode change 100755 => 100644 bsnes/target-ethos/configuration/configuration.hpp mode change 100755 => 100644 bsnes/target-ethos/ethos.cpp mode change 100755 => 100644 bsnes/target-ethos/ethos.hpp mode change 100755 => 100644 bsnes/target-ethos/general/browser.cpp mode change 100755 => 100644 bsnes/target-ethos/general/browser.hpp mode change 100755 => 100644 bsnes/target-ethos/general/dip-switches.cpp mode change 100755 => 100644 bsnes/target-ethos/general/dip-switches.hpp mode change 100755 => 100644 bsnes/target-ethos/general/general.cpp mode change 100755 => 100644 bsnes/target-ethos/general/general.hpp mode change 100755 => 100644 bsnes/target-ethos/general/presentation.cpp mode change 100755 => 100644 bsnes/target-ethos/general/presentation.hpp mode change 100755 => 100644 bsnes/target-ethos/input/hotkeys.cpp mode change 100755 => 100644 bsnes/target-ethos/input/input.cpp mode change 100755 => 100644 bsnes/target-ethos/input/input.hpp mode change 100755 => 100644 bsnes/target-ethos/interface/interface.cpp mode change 100755 => 100644 bsnes/target-ethos/interface/interface.hpp mode change 100755 => 100644 bsnes/target-ethos/resource.rc mode change 100755 => 100644 bsnes/target-ethos/resource/folder.png mode change 100755 => 100644 bsnes/target-ethos/resource/game.png mode change 100755 => 100644 bsnes/target-ethos/resource/home.png mode change 100755 => 100644 bsnes/target-ethos/resource/resource.cpp mode change 100755 => 100644 bsnes/target-ethos/resource/resource.hpp mode change 100755 => 100644 bsnes/target-ethos/resource/resource.xml mode change 100755 => 100644 bsnes/target-ethos/resource/up.png mode change 100755 => 100644 bsnes/target-ethos/settings/audio.cpp mode change 100755 => 100644 bsnes/target-ethos/settings/audio.hpp mode change 100755 => 100644 bsnes/target-ethos/settings/driver.cpp mode change 100755 => 100644 bsnes/target-ethos/settings/driver.hpp mode change 100755 => 100644 bsnes/target-ethos/settings/hotkey.cpp mode change 100755 => 100644 bsnes/target-ethos/settings/hotkey.hpp mode change 100755 => 100644 bsnes/target-ethos/settings/input.cpp mode change 100755 => 100644 bsnes/target-ethos/settings/input.hpp mode change 100755 => 100644 bsnes/target-ethos/settings/settings.cpp mode change 100755 => 100644 bsnes/target-ethos/settings/settings.hpp mode change 100755 => 100644 bsnes/target-ethos/settings/timing.cpp mode change 100755 => 100644 bsnes/target-ethos/settings/timing.hpp mode change 100755 => 100644 bsnes/target-ethos/settings/video.cpp mode change 100755 => 100644 bsnes/target-ethos/settings/video.hpp mode change 100755 => 100644 bsnes/target-ethos/tools/cheat-database.cpp mode change 100755 => 100644 bsnes/target-ethos/tools/cheat-database.hpp mode change 100755 => 100644 bsnes/target-ethos/tools/cheat-editor.cpp mode change 100755 => 100644 bsnes/target-ethos/tools/cheat-editor.hpp mode change 100755 => 100644 bsnes/target-ethos/tools/state-manager.cpp mode change 100755 => 100644 bsnes/target-ethos/tools/state-manager.hpp mode change 100755 => 100644 bsnes/target-ethos/tools/tools.cpp mode change 100755 => 100644 bsnes/target-ethos/tools/tools.hpp mode change 100755 => 100644 bsnes/target-ethos/utility/utility.cpp mode change 100755 => 100644 bsnes/target-ethos/utility/utility.hpp mode change 100755 => 100644 bsnes/target-ethos/window/window.cpp mode change 100755 => 100644 bsnes/target-ethos/window/window.hpp mode change 100755 => 100644 bsnes/target-laevateinn/Makefile mode change 100755 => 100644 bsnes/target-laevateinn/base.hpp mode change 100755 => 100644 bsnes/target-laevateinn/breakpoint/breakpoint.cpp mode change 100755 => 100644 bsnes/target-laevateinn/breakpoint/breakpoint.hpp mode change 100755 => 100644 bsnes/target-laevateinn/console/about.cpp mode change 100755 => 100644 bsnes/target-laevateinn/console/console.cpp mode change 100755 => 100644 bsnes/target-laevateinn/console/console.hpp mode change 100755 => 100644 bsnes/target-laevateinn/cpu/cpu.cpp mode change 100755 => 100644 bsnes/target-laevateinn/cpu/cpu.hpp mode change 100755 => 100644 bsnes/target-laevateinn/cpu/registers.cpp mode change 100755 => 100644 bsnes/target-laevateinn/debugger/debugger.cpp mode change 100755 => 100644 bsnes/target-laevateinn/debugger/debugger.hpp mode change 100755 => 100644 bsnes/target-laevateinn/debugger/hook.cpp mode change 100755 => 100644 bsnes/target-laevateinn/debugger/usage.cpp mode change 100755 => 100644 bsnes/target-laevateinn/interface/interface.cpp mode change 100755 => 100644 bsnes/target-laevateinn/interface/interface.hpp mode change 100755 => 100644 bsnes/target-laevateinn/main.cpp mode change 100755 => 100644 bsnes/target-laevateinn/memory/memory.cpp mode change 100755 => 100644 bsnes/target-laevateinn/memory/memory.hpp mode change 100755 => 100644 bsnes/target-laevateinn/properties/properties.cpp mode change 100755 => 100644 bsnes/target-laevateinn/properties/properties.hpp mode change 100755 => 100644 bsnes/target-laevateinn/resource.rc mode change 100755 => 100644 bsnes/target-laevateinn/settings/settings.cpp mode change 100755 => 100644 bsnes/target-laevateinn/settings/settings.hpp mode change 100755 => 100644 bsnes/target-laevateinn/smp/registers.cpp mode change 100755 => 100644 bsnes/target-laevateinn/smp/smp.cpp mode change 100755 => 100644 bsnes/target-laevateinn/smp/smp.hpp mode change 100755 => 100644 bsnes/target-laevateinn/tracer/tracer.cpp mode change 100755 => 100644 bsnes/target-laevateinn/tracer/tracer.hpp mode change 100755 => 100644 bsnes/target-laevateinn/video/video.cpp mode change 100755 => 100644 bsnes/target-laevateinn/video/video.hpp mode change 100755 => 100644 bsnes/target-laevateinn/vram/vram.cpp mode change 100755 => 100644 bsnes/target-laevateinn/vram/vram.hpp mode change 100755 => 100644 bsnes/target-laevateinn/window/window.cpp mode change 100755 => 100644 bsnes/target-laevateinn/window/window.hpp create mode 100644 kaijuu/Makefile create mode 100755 kaijuu/cc32.bat create mode 100755 kaijuu/cc64.bat create mode 100644 kaijuu/extension.cpp create mode 100644 kaijuu/extension.hpp create mode 100644 kaijuu/factory.cpp create mode 100644 kaijuu/factory.hpp create mode 100644 kaijuu/guid.hpp create mode 100644 kaijuu/interface.cpp create mode 100644 kaijuu/interface.hpp create mode 100644 kaijuu/kaijuu.Manifest create mode 100644 kaijuu/kaijuu.cpp create mode 100644 kaijuu/kaijuu.def create mode 100644 kaijuu/kaijuu.hpp create mode 100644 kaijuu/kaijuu.html create mode 100644 kaijuu/kaijuu.rc rename {snesfilter => kaijuu}/nall/Makefile (90%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/algorithm.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/any.hpp (84%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/atoi.hpp (82%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/base64.hpp (100%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/bit.hpp rename {snesfilter => kaijuu}/nall/bmp.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/bps/delta.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/bps/linear.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/bps/metadata.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/bps/patch.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/compositor.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/config.hpp (76%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/crc32.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/directory.hpp (77%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dl.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp/buffer.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp/core.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp/resample/average.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp/resample/cosine.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp/resample/cubic.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp/resample/hermite.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp/resample/lib/sinc.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp/resample/linear.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp/resample/nearest.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp/resample/sinc.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/dsp/settings.hpp (100%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/emulation/famicom.hpp create mode 100644 kaijuu/nall/emulation/game-boy-advance.hpp rename snesfilter/nall/gameboy/cartridge.hpp => kaijuu/nall/emulation/game-boy.hpp (85%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/emulation/satellaview.hpp create mode 100644 kaijuu/nall/emulation/sufami-turbo.hpp create mode 100644 kaijuu/nall/emulation/super-famicom-usart.hpp create mode 100644 kaijuu/nall/emulation/super-famicom.hpp rename {snesfilter => kaijuu}/nall/endian.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/file.hpp (81%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/filemap.hpp (99%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/function.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/gzip.hpp (83%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/http.hpp (99%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/image.hpp (75%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/inflate.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/input.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/interpolation.hpp (91%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/intrinsics.hpp (100%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/invoke.hpp rename {snesfilter => kaijuu}/nall/ips.hpp (89%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/lzss.hpp (100%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/map.hpp create mode 100644 kaijuu/nall/mosaic.hpp create mode 100644 kaijuu/nall/mosaic/bitstream.hpp create mode 100644 kaijuu/nall/mosaic/context.hpp create mode 100644 kaijuu/nall/mosaic/parser.hpp create mode 100644 kaijuu/nall/nall.hpp create mode 100644 kaijuu/nall/platform.hpp rename {snesfilter => kaijuu}/nall/png.hpp (98%) mode change 100755 => 100644 rename snesfilter/nall/priorityqueue.hpp => kaijuu/nall/priority-queue.hpp (97%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/property.hpp (100%) mode change 100755 => 100644 rename snesfilter/nall/public_cast.hpp => kaijuu/nall/public-cast.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/random.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/serial.hpp (73%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/serializer.hpp (94%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/set.hpp rename {snesfilter => kaijuu}/nall/sha256.hpp (100%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/sort.hpp rename {snesfilter => kaijuu}/nall/stdint.hpp (97%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/stream.hpp create mode 100644 kaijuu/nall/stream/auto.hpp create mode 100644 kaijuu/nall/stream/file.hpp create mode 100644 kaijuu/nall/stream/gzip.hpp create mode 100644 kaijuu/nall/stream/http.hpp create mode 100644 kaijuu/nall/stream/memory.hpp create mode 100644 kaijuu/nall/stream/mmap.hpp create mode 100644 kaijuu/nall/stream/stream.hpp create mode 100644 kaijuu/nall/stream/vector.hpp create mode 100644 kaijuu/nall/stream/zip.hpp rename {snesfilter => kaijuu}/nall/string.hpp (92%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/base.hpp (87%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/bml.hpp (97%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/bsv.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/cast.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/compare.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/convert.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/core.hpp (76%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/cstring.hpp (100%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/string/filename.hpp rename {snesfilter => kaijuu}/nall/string/math-fixed-point.hpp (96%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/math-floating-point.hpp (96%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/string/platform.hpp rename {snesfilter => kaijuu}/nall/string/replace.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/split.hpp (100%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/string/static.hpp create mode 100644 kaijuu/nall/string/strm.hpp rename {snesfilter => kaijuu}/nall/string/strpos.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/trim.hpp (100%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/string/utf8.hpp rename {snesfilter => kaijuu}/nall/string/utility.hpp (94%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/variadic.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/wildcard.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/string/wrapper.hpp (97%) mode change 100755 => 100644 rename snesfilter/nall/string/xml.hpp => kaijuu/nall/string/xml-legacy.hpp (100%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/string/xml.hpp create mode 100644 kaijuu/nall/traits.hpp create mode 100644 kaijuu/nall/udl.hpp rename {snesfilter => kaijuu}/nall/ups.hpp (100%) mode change 100755 => 100644 rename {snesfilter => kaijuu}/nall/utility.hpp (71%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/varint.hpp create mode 100644 kaijuu/nall/vector.hpp rename {snesfilter => kaijuu}/nall/windows/detour.hpp (100%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/windows/guid.hpp rename {snesfilter => kaijuu}/nall/windows/launcher.hpp (100%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/windows/registry.hpp rename {snesfilter => kaijuu}/nall/windows/utf8.hpp (98%) mode change 100755 => 100644 create mode 100644 kaijuu/nall/xorg/guard.hpp create mode 100644 kaijuu/nall/xorg/xorg.hpp rename {snesfilter => kaijuu}/nall/zip.hpp (79%) mode change 100755 => 100644 create mode 100644 kaijuu/phoenix/Makefile create mode 100644 kaijuu/phoenix/core/core.cpp create mode 100644 kaijuu/phoenix/core/core.hpp create mode 100644 kaijuu/phoenix/core/keyboard.hpp create mode 100644 kaijuu/phoenix/core/layout/fixed-layout.cpp create mode 100644 kaijuu/phoenix/core/layout/fixed-layout.hpp create mode 100644 kaijuu/phoenix/core/layout/horizontal-layout.cpp create mode 100644 kaijuu/phoenix/core/layout/horizontal-layout.hpp create mode 100644 kaijuu/phoenix/core/layout/vertical-layout.cpp create mode 100644 kaijuu/phoenix/core/layout/vertical-layout.hpp create mode 100644 kaijuu/phoenix/core/state.hpp create mode 100644 kaijuu/phoenix/gtk/action/action.cpp create mode 100644 kaijuu/phoenix/gtk/action/check-item.cpp create mode 100644 kaijuu/phoenix/gtk/action/item.cpp create mode 100644 kaijuu/phoenix/gtk/action/menu.cpp create mode 100644 kaijuu/phoenix/gtk/action/radio-item.cpp create mode 100644 kaijuu/phoenix/gtk/action/separator.cpp create mode 100644 kaijuu/phoenix/gtk/desktop.cpp create mode 100644 kaijuu/phoenix/gtk/dialog-window.cpp create mode 100644 kaijuu/phoenix/gtk/font.cpp create mode 100644 kaijuu/phoenix/gtk/keyboard.cpp create mode 100644 kaijuu/phoenix/gtk/message-window.cpp create mode 100644 kaijuu/phoenix/gtk/mouse.cpp create mode 100644 kaijuu/phoenix/gtk/platform.cpp create mode 100644 kaijuu/phoenix/gtk/platform.hpp create mode 100644 kaijuu/phoenix/gtk/settings.cpp create mode 100644 kaijuu/phoenix/gtk/timer.cpp create mode 100644 kaijuu/phoenix/gtk/utility.cpp create mode 100644 kaijuu/phoenix/gtk/widget/button.cpp create mode 100644 kaijuu/phoenix/gtk/widget/canvas.cpp create mode 100644 kaijuu/phoenix/gtk/widget/check-box.cpp create mode 100644 kaijuu/phoenix/gtk/widget/combo-box.cpp create mode 100644 kaijuu/phoenix/gtk/widget/hex-edit.cpp create mode 100644 kaijuu/phoenix/gtk/widget/horizontal-scroll-bar.cpp create mode 100644 kaijuu/phoenix/gtk/widget/horizontal-slider.cpp create mode 100644 kaijuu/phoenix/gtk/widget/label.cpp create mode 100644 kaijuu/phoenix/gtk/widget/line-edit.cpp create mode 100644 kaijuu/phoenix/gtk/widget/list-view.cpp create mode 100644 kaijuu/phoenix/gtk/widget/progress-bar.cpp create mode 100644 kaijuu/phoenix/gtk/widget/radio-box.cpp create mode 100644 kaijuu/phoenix/gtk/widget/text-edit.cpp create mode 100644 kaijuu/phoenix/gtk/widget/vertical-scroll-bar.cpp create mode 100644 kaijuu/phoenix/gtk/widget/vertical-slider.cpp create mode 100644 kaijuu/phoenix/gtk/widget/viewport.cpp create mode 100644 kaijuu/phoenix/gtk/widget/widget.cpp create mode 100644 kaijuu/phoenix/gtk/window.cpp create mode 100644 kaijuu/phoenix/phoenix.cpp create mode 100644 kaijuu/phoenix/phoenix.hpp create mode 100644 kaijuu/phoenix/qt/action/action.cpp create mode 100644 kaijuu/phoenix/qt/action/check-item.cpp create mode 100644 kaijuu/phoenix/qt/action/item.cpp create mode 100644 kaijuu/phoenix/qt/action/menu.cpp create mode 100644 kaijuu/phoenix/qt/action/radio-item.cpp create mode 100644 kaijuu/phoenix/qt/action/separator.cpp create mode 100644 kaijuu/phoenix/qt/desktop.cpp create mode 100644 kaijuu/phoenix/qt/dialog-window.cpp create mode 100644 kaijuu/phoenix/qt/font.cpp create mode 100644 kaijuu/phoenix/qt/keyboard.cpp create mode 100644 kaijuu/phoenix/qt/message-window.cpp create mode 100644 kaijuu/phoenix/qt/mouse.cpp create mode 100644 kaijuu/phoenix/qt/platform.cpp create mode 100644 kaijuu/phoenix/qt/platform.moc create mode 100644 kaijuu/phoenix/qt/platform.moc.hpp create mode 100644 kaijuu/phoenix/qt/settings.cpp create mode 100644 kaijuu/phoenix/qt/timer.cpp create mode 100644 kaijuu/phoenix/qt/utility.cpp create mode 100644 kaijuu/phoenix/qt/widget/button.cpp create mode 100644 kaijuu/phoenix/qt/widget/canvas.cpp create mode 100644 kaijuu/phoenix/qt/widget/check-box.cpp create mode 100644 kaijuu/phoenix/qt/widget/combo-box.cpp create mode 100644 kaijuu/phoenix/qt/widget/hex-edit.cpp create mode 100644 kaijuu/phoenix/qt/widget/horizontal-scroll-bar.cpp create mode 100644 kaijuu/phoenix/qt/widget/horizontal-slider.cpp create mode 100644 kaijuu/phoenix/qt/widget/label.cpp create mode 100644 kaijuu/phoenix/qt/widget/line-edit.cpp create mode 100644 kaijuu/phoenix/qt/widget/list-view.cpp create mode 100644 kaijuu/phoenix/qt/widget/progress-bar.cpp create mode 100644 kaijuu/phoenix/qt/widget/radio-box.cpp create mode 100644 kaijuu/phoenix/qt/widget/text-edit.cpp create mode 100644 kaijuu/phoenix/qt/widget/vertical-scroll-bar.cpp create mode 100644 kaijuu/phoenix/qt/widget/vertical-slider.cpp create mode 100644 kaijuu/phoenix/qt/widget/viewport.cpp create mode 100644 kaijuu/phoenix/qt/widget/widget.cpp create mode 100644 kaijuu/phoenix/qt/window.cpp create mode 100644 kaijuu/phoenix/reference/action/action.cpp create mode 100644 kaijuu/phoenix/reference/action/check-item.cpp create mode 100644 kaijuu/phoenix/reference/action/item.cpp create mode 100644 kaijuu/phoenix/reference/action/menu.cpp create mode 100644 kaijuu/phoenix/reference/action/radio-item.cpp create mode 100644 kaijuu/phoenix/reference/action/separator.cpp create mode 100644 kaijuu/phoenix/reference/desktop.cpp create mode 100644 kaijuu/phoenix/reference/dialog-window.cpp create mode 100644 kaijuu/phoenix/reference/font.cpp create mode 100644 kaijuu/phoenix/reference/keyboard.cpp create mode 100644 kaijuu/phoenix/reference/message-window.cpp create mode 100644 kaijuu/phoenix/reference/mouse.cpp create mode 100644 kaijuu/phoenix/reference/platform.cpp create mode 100644 kaijuu/phoenix/reference/platform.hpp create mode 100644 kaijuu/phoenix/reference/timer.cpp create mode 100644 kaijuu/phoenix/reference/widget/button.cpp create mode 100644 kaijuu/phoenix/reference/widget/canvas.cpp create mode 100644 kaijuu/phoenix/reference/widget/check-box.cpp create mode 100644 kaijuu/phoenix/reference/widget/combo-box.cpp create mode 100644 kaijuu/phoenix/reference/widget/hex-edit.cpp create mode 100644 kaijuu/phoenix/reference/widget/horizontal-scroll-bar.cpp create mode 100644 kaijuu/phoenix/reference/widget/horizontal-slider.cpp create mode 100644 kaijuu/phoenix/reference/widget/label.cpp create mode 100644 kaijuu/phoenix/reference/widget/line-edit.cpp create mode 100644 kaijuu/phoenix/reference/widget/list-view.cpp create mode 100644 kaijuu/phoenix/reference/widget/progress-bar.cpp create mode 100644 kaijuu/phoenix/reference/widget/radio-box.cpp create mode 100644 kaijuu/phoenix/reference/widget/text-edit.cpp create mode 100644 kaijuu/phoenix/reference/widget/vertical-scroll-bar.cpp create mode 100644 kaijuu/phoenix/reference/widget/vertical-slider.cpp create mode 100644 kaijuu/phoenix/reference/widget/viewport.cpp create mode 100644 kaijuu/phoenix/reference/widget/widget.cpp create mode 100644 kaijuu/phoenix/reference/window.cpp rename {snesfilter => kaijuu/phoenix}/sync.sh (88%) mode change 100755 => 100644 create mode 100644 kaijuu/phoenix/windows/action/action.cpp create mode 100644 kaijuu/phoenix/windows/action/check-item.cpp create mode 100644 kaijuu/phoenix/windows/action/item.cpp create mode 100644 kaijuu/phoenix/windows/action/menu.cpp create mode 100644 kaijuu/phoenix/windows/action/radio-item.cpp create mode 100644 kaijuu/phoenix/windows/action/separator.cpp create mode 100644 kaijuu/phoenix/windows/desktop.cpp create mode 100644 kaijuu/phoenix/windows/dialog-window.cpp create mode 100644 kaijuu/phoenix/windows/font.cpp create mode 100644 kaijuu/phoenix/windows/keyboard.cpp create mode 100644 kaijuu/phoenix/windows/message-window.cpp create mode 100644 kaijuu/phoenix/windows/mouse.cpp create mode 100644 kaijuu/phoenix/windows/object.cpp create mode 100644 kaijuu/phoenix/windows/phoenix.Manifest create mode 100644 kaijuu/phoenix/windows/phoenix.rc create mode 100644 kaijuu/phoenix/windows/platform.cpp create mode 100644 kaijuu/phoenix/windows/platform.hpp create mode 100644 kaijuu/phoenix/windows/settings.cpp create mode 100644 kaijuu/phoenix/windows/timer.cpp create mode 100644 kaijuu/phoenix/windows/utility.cpp create mode 100644 kaijuu/phoenix/windows/widget/button.cpp create mode 100644 kaijuu/phoenix/windows/widget/canvas.cpp create mode 100644 kaijuu/phoenix/windows/widget/check-box.cpp create mode 100644 kaijuu/phoenix/windows/widget/combo-box.cpp create mode 100644 kaijuu/phoenix/windows/widget/hex-edit.cpp create mode 100644 kaijuu/phoenix/windows/widget/horizontal-scroll-bar.cpp create mode 100644 kaijuu/phoenix/windows/widget/horizontal-slider.cpp create mode 100644 kaijuu/phoenix/windows/widget/label.cpp create mode 100644 kaijuu/phoenix/windows/widget/line-edit.cpp create mode 100644 kaijuu/phoenix/windows/widget/list-view.cpp create mode 100644 kaijuu/phoenix/windows/widget/progress-bar.cpp create mode 100644 kaijuu/phoenix/windows/widget/radio-box.cpp create mode 100644 kaijuu/phoenix/windows/widget/text-edit.cpp create mode 100644 kaijuu/phoenix/windows/widget/vertical-scroll-bar.cpp create mode 100644 kaijuu/phoenix/windows/widget/vertical-slider.cpp create mode 100644 kaijuu/phoenix/windows/widget/viewport.cpp create mode 100644 kaijuu/phoenix/windows/widget/widget.cpp create mode 100644 kaijuu/phoenix/windows/window.cpp create mode 100644 kaijuu/resource/kaijuu.png create mode 100644 kaijuu/resource/resource.cpp create mode 100644 kaijuu/resource/resource.hpp create mode 100644 kaijuu/resource/resource.xml create mode 100644 kaijuu/settings.hpp create mode 100644 kaijuu/sync.sh mode change 100755 => 100644 purify/Makefile mode change 100755 => 100644 purify/nall/Makefile mode change 100755 => 100644 purify/nall/algorithm.hpp mode change 100755 => 100644 purify/nall/any.hpp mode change 100755 => 100644 purify/nall/atoi.hpp mode change 100755 => 100644 purify/nall/base64.hpp mode change 100755 => 100644 purify/nall/bit.hpp mode change 100755 => 100644 purify/nall/bmp.hpp mode change 100755 => 100644 purify/nall/bps/delta.hpp mode change 100755 => 100644 purify/nall/bps/linear.hpp mode change 100755 => 100644 purify/nall/bps/metadata.hpp mode change 100755 => 100644 purify/nall/bps/patch.hpp mode change 100755 => 100644 purify/nall/compositor.hpp mode change 100755 => 100644 purify/nall/config.hpp mode change 100755 => 100644 purify/nall/crc32.hpp mode change 100755 => 100644 purify/nall/directory.hpp mode change 100755 => 100644 purify/nall/dl.hpp mode change 100755 => 100644 purify/nall/dsp.hpp mode change 100755 => 100644 purify/nall/dsp/buffer.hpp mode change 100755 => 100644 purify/nall/dsp/core.hpp mode change 100755 => 100644 purify/nall/dsp/resample/average.hpp mode change 100755 => 100644 purify/nall/dsp/resample/cosine.hpp mode change 100755 => 100644 purify/nall/dsp/resample/cubic.hpp mode change 100755 => 100644 purify/nall/dsp/resample/hermite.hpp mode change 100755 => 100644 purify/nall/dsp/resample/lib/sinc.hpp mode change 100755 => 100644 purify/nall/dsp/resample/linear.hpp mode change 100755 => 100644 purify/nall/dsp/resample/nearest.hpp mode change 100755 => 100644 purify/nall/dsp/resample/sinc.hpp mode change 100755 => 100644 purify/nall/dsp/settings.hpp mode change 100755 => 100644 purify/nall/emulation/famicom.hpp mode change 100755 => 100644 purify/nall/emulation/game-boy-advance.hpp mode change 100755 => 100644 purify/nall/emulation/game-boy.hpp mode change 100755 => 100644 purify/nall/emulation/satellaview.hpp mode change 100755 => 100644 purify/nall/emulation/sufami-turbo.hpp mode change 100755 => 100644 purify/nall/emulation/super-famicom-usart.hpp mode change 100755 => 100644 purify/nall/emulation/super-famicom.hpp mode change 100755 => 100644 purify/nall/endian.hpp mode change 100755 => 100644 purify/nall/file.hpp mode change 100755 => 100644 purify/nall/filemap.hpp mode change 100755 => 100644 purify/nall/function.hpp mode change 100755 => 100644 purify/nall/gzip.hpp mode change 100755 => 100644 purify/nall/http.hpp mode change 100755 => 100644 purify/nall/image.hpp mode change 100755 => 100644 purify/nall/inflate.hpp mode change 100755 => 100644 purify/nall/input.hpp mode change 100755 => 100644 purify/nall/interpolation.hpp mode change 100755 => 100644 purify/nall/intrinsics.hpp mode change 100755 => 100644 purify/nall/invoke.hpp mode change 100755 => 100644 purify/nall/ips.hpp mode change 100755 => 100644 purify/nall/lzss.hpp mode change 100755 => 100644 purify/nall/map.hpp mode change 100755 => 100644 purify/nall/mosaic.hpp mode change 100755 => 100644 purify/nall/mosaic/bitstream.hpp mode change 100755 => 100644 purify/nall/mosaic/context.hpp mode change 100755 => 100644 purify/nall/mosaic/parser.hpp mode change 100755 => 100644 purify/nall/nall.hpp mode change 100755 => 100644 purify/nall/platform.hpp mode change 100755 => 100644 purify/nall/png.hpp mode change 100755 => 100644 purify/nall/priority-queue.hpp mode change 100755 => 100644 purify/nall/property.hpp mode change 100755 => 100644 purify/nall/public-cast.hpp mode change 100755 => 100644 purify/nall/random.hpp mode change 100755 => 100644 purify/nall/serial.hpp mode change 100755 => 100644 purify/nall/serializer.hpp mode change 100755 => 100644 purify/nall/set.hpp mode change 100755 => 100644 purify/nall/sha256.hpp mode change 100755 => 100644 purify/nall/sort.hpp mode change 100755 => 100644 purify/nall/stdint.hpp mode change 100755 => 100644 purify/nall/stream.hpp mode change 100755 => 100644 purify/nall/stream/auto.hpp mode change 100755 => 100644 purify/nall/stream/file.hpp mode change 100755 => 100644 purify/nall/stream/gzip.hpp mode change 100755 => 100644 purify/nall/stream/http.hpp mode change 100755 => 100644 purify/nall/stream/memory.hpp mode change 100755 => 100644 purify/nall/stream/mmap.hpp mode change 100755 => 100644 purify/nall/stream/stream.hpp mode change 100755 => 100644 purify/nall/stream/vector.hpp mode change 100755 => 100644 purify/nall/stream/zip.hpp mode change 100755 => 100644 purify/nall/string.hpp mode change 100755 => 100644 purify/nall/string/base.hpp mode change 100755 => 100644 purify/nall/string/bml.hpp mode change 100755 => 100644 purify/nall/string/bsv.hpp mode change 100755 => 100644 purify/nall/string/cast.hpp mode change 100755 => 100644 purify/nall/string/compare.hpp mode change 100755 => 100644 purify/nall/string/convert.hpp mode change 100755 => 100644 purify/nall/string/core.hpp mode change 100755 => 100644 purify/nall/string/cstring.hpp mode change 100755 => 100644 purify/nall/string/filename.hpp mode change 100755 => 100644 purify/nall/string/math-fixed-point.hpp mode change 100755 => 100644 purify/nall/string/math-floating-point.hpp mode change 100755 => 100644 purify/nall/string/platform.hpp mode change 100755 => 100644 purify/nall/string/replace.hpp mode change 100755 => 100644 purify/nall/string/split.hpp mode change 100755 => 100644 purify/nall/string/static.hpp mode change 100755 => 100644 purify/nall/string/strm.hpp mode change 100755 => 100644 purify/nall/string/strpos.hpp mode change 100755 => 100644 purify/nall/string/trim.hpp mode change 100755 => 100644 purify/nall/string/utf8.hpp mode change 100755 => 100644 purify/nall/string/utility.hpp mode change 100755 => 100644 purify/nall/string/variadic.hpp mode change 100755 => 100644 purify/nall/string/wildcard.hpp mode change 100755 => 100644 purify/nall/string/wrapper.hpp mode change 100755 => 100644 purify/nall/string/xml-legacy.hpp mode change 100755 => 100644 purify/nall/string/xml.hpp mode change 100755 => 100644 purify/nall/traits.hpp mode change 100755 => 100644 purify/nall/udl.hpp mode change 100755 => 100644 purify/nall/ups.hpp mode change 100755 => 100644 purify/nall/utility.hpp mode change 100755 => 100644 purify/nall/varint.hpp mode change 100755 => 100644 purify/nall/vector.hpp mode change 100755 => 100644 purify/nall/windows/detour.hpp mode change 100755 => 100644 purify/nall/windows/guid.hpp mode change 100755 => 100644 purify/nall/windows/launcher.hpp mode change 100755 => 100644 purify/nall/windows/registry.hpp mode change 100755 => 100644 purify/nall/windows/utf8.hpp mode change 100755 => 100644 purify/nall/xorg/guard.hpp mode change 100755 => 100644 purify/nall/xorg/xorg.hpp mode change 100755 => 100644 purify/nall/zip.hpp mode change 100755 => 100644 purify/phoenix/Makefile mode change 100755 => 100644 purify/phoenix/core/core.cpp mode change 100755 => 100644 purify/phoenix/core/core.hpp mode change 100755 => 100644 purify/phoenix/core/keyboard.hpp mode change 100755 => 100644 purify/phoenix/core/layout/fixed-layout.cpp mode change 100755 => 100644 purify/phoenix/core/layout/fixed-layout.hpp mode change 100755 => 100644 purify/phoenix/core/layout/horizontal-layout.cpp mode change 100755 => 100644 purify/phoenix/core/layout/horizontal-layout.hpp mode change 100755 => 100644 purify/phoenix/core/layout/vertical-layout.cpp mode change 100755 => 100644 purify/phoenix/core/layout/vertical-layout.hpp mode change 100755 => 100644 purify/phoenix/core/state.hpp mode change 100755 => 100644 purify/phoenix/gtk/action/action.cpp mode change 100755 => 100644 purify/phoenix/gtk/action/check-item.cpp mode change 100755 => 100644 purify/phoenix/gtk/action/item.cpp mode change 100755 => 100644 purify/phoenix/gtk/action/menu.cpp mode change 100755 => 100644 purify/phoenix/gtk/action/radio-item.cpp mode change 100755 => 100644 purify/phoenix/gtk/action/separator.cpp mode change 100755 => 100644 purify/phoenix/gtk/desktop.cpp mode change 100755 => 100644 purify/phoenix/gtk/dialog-window.cpp mode change 100755 => 100644 purify/phoenix/gtk/font.cpp mode change 100755 => 100644 purify/phoenix/gtk/keyboard.cpp mode change 100755 => 100644 purify/phoenix/gtk/message-window.cpp mode change 100755 => 100644 purify/phoenix/gtk/mouse.cpp mode change 100755 => 100644 purify/phoenix/gtk/platform.cpp mode change 100755 => 100644 purify/phoenix/gtk/platform.hpp mode change 100755 => 100644 purify/phoenix/gtk/settings.cpp mode change 100755 => 100644 purify/phoenix/gtk/timer.cpp mode change 100755 => 100644 purify/phoenix/gtk/utility.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/button.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/canvas.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/check-box.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/combo-box.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/hex-edit.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/horizontal-scroll-bar.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/horizontal-slider.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/label.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/line-edit.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/list-view.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/progress-bar.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/radio-box.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/text-edit.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/vertical-scroll-bar.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/vertical-slider.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/viewport.cpp mode change 100755 => 100644 purify/phoenix/gtk/widget/widget.cpp mode change 100755 => 100644 purify/phoenix/gtk/window.cpp mode change 100755 => 100644 purify/phoenix/phoenix.cpp mode change 100755 => 100644 purify/phoenix/phoenix.hpp mode change 100755 => 100644 purify/phoenix/qt/action/action.cpp mode change 100755 => 100644 purify/phoenix/qt/action/check-item.cpp mode change 100755 => 100644 purify/phoenix/qt/action/item.cpp mode change 100755 => 100644 purify/phoenix/qt/action/menu.cpp mode change 100755 => 100644 purify/phoenix/qt/action/radio-item.cpp mode change 100755 => 100644 purify/phoenix/qt/action/separator.cpp mode change 100755 => 100644 purify/phoenix/qt/desktop.cpp mode change 100755 => 100644 purify/phoenix/qt/dialog-window.cpp mode change 100755 => 100644 purify/phoenix/qt/font.cpp mode change 100755 => 100644 purify/phoenix/qt/keyboard.cpp mode change 100755 => 100644 purify/phoenix/qt/message-window.cpp mode change 100755 => 100644 purify/phoenix/qt/mouse.cpp mode change 100755 => 100644 purify/phoenix/qt/platform.cpp mode change 100755 => 100644 purify/phoenix/qt/platform.moc mode change 100755 => 100644 purify/phoenix/qt/platform.moc.hpp mode change 100755 => 100644 purify/phoenix/qt/settings.cpp mode change 100755 => 100644 purify/phoenix/qt/timer.cpp mode change 100755 => 100644 purify/phoenix/qt/utility.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/button.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/canvas.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/check-box.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/combo-box.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/hex-edit.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/horizontal-scroll-bar.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/horizontal-slider.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/label.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/line-edit.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/list-view.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/progress-bar.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/radio-box.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/text-edit.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/vertical-scroll-bar.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/vertical-slider.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/viewport.cpp mode change 100755 => 100644 purify/phoenix/qt/widget/widget.cpp mode change 100755 => 100644 purify/phoenix/qt/window.cpp mode change 100755 => 100644 purify/phoenix/reference/action/action.cpp mode change 100755 => 100644 purify/phoenix/reference/action/check-item.cpp mode change 100755 => 100644 purify/phoenix/reference/action/item.cpp mode change 100755 => 100644 purify/phoenix/reference/action/menu.cpp mode change 100755 => 100644 purify/phoenix/reference/action/radio-item.cpp mode change 100755 => 100644 purify/phoenix/reference/action/separator.cpp mode change 100755 => 100644 purify/phoenix/reference/desktop.cpp mode change 100755 => 100644 purify/phoenix/reference/dialog-window.cpp mode change 100755 => 100644 purify/phoenix/reference/font.cpp mode change 100755 => 100644 purify/phoenix/reference/keyboard.cpp mode change 100755 => 100644 purify/phoenix/reference/message-window.cpp mode change 100755 => 100644 purify/phoenix/reference/mouse.cpp mode change 100755 => 100644 purify/phoenix/reference/platform.cpp mode change 100755 => 100644 purify/phoenix/reference/platform.hpp mode change 100755 => 100644 purify/phoenix/reference/timer.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/button.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/canvas.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/check-box.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/combo-box.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/hex-edit.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/horizontal-scroll-bar.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/horizontal-slider.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/label.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/line-edit.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/list-view.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/progress-bar.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/radio-box.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/text-edit.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/vertical-scroll-bar.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/vertical-slider.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/viewport.cpp mode change 100755 => 100644 purify/phoenix/reference/widget/widget.cpp mode change 100755 => 100644 purify/phoenix/reference/window.cpp mode change 100755 => 100644 purify/phoenix/sync.sh mode change 100755 => 100644 purify/phoenix/windows/action/action.cpp mode change 100755 => 100644 purify/phoenix/windows/action/check-item.cpp mode change 100755 => 100644 purify/phoenix/windows/action/item.cpp mode change 100755 => 100644 purify/phoenix/windows/action/menu.cpp mode change 100755 => 100644 purify/phoenix/windows/action/radio-item.cpp mode change 100755 => 100644 purify/phoenix/windows/action/separator.cpp mode change 100755 => 100644 purify/phoenix/windows/desktop.cpp mode change 100755 => 100644 purify/phoenix/windows/dialog-window.cpp mode change 100755 => 100644 purify/phoenix/windows/font.cpp mode change 100755 => 100644 purify/phoenix/windows/keyboard.cpp mode change 100755 => 100644 purify/phoenix/windows/message-window.cpp mode change 100755 => 100644 purify/phoenix/windows/mouse.cpp mode change 100755 => 100644 purify/phoenix/windows/object.cpp mode change 100755 => 100644 purify/phoenix/windows/phoenix.Manifest mode change 100755 => 100644 purify/phoenix/windows/phoenix.rc mode change 100755 => 100644 purify/phoenix/windows/platform.cpp mode change 100755 => 100644 purify/phoenix/windows/platform.hpp mode change 100755 => 100644 purify/phoenix/windows/settings.cpp mode change 100755 => 100644 purify/phoenix/windows/timer.cpp mode change 100755 => 100644 purify/phoenix/windows/utility.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/button.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/canvas.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/check-box.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/combo-box.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/hex-edit.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/horizontal-scroll-bar.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/horizontal-slider.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/label.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/line-edit.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/list-view.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/progress-bar.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/radio-box.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/text-edit.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/vertical-scroll-bar.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/vertical-slider.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/viewport.cpp mode change 100755 => 100644 purify/phoenix/windows/widget/widget.cpp mode change 100755 => 100644 purify/phoenix/windows/window.cpp mode change 100755 => 100644 purify/purify.cpp mode change 100755 => 100644 purify/resource/applications-system.png mode change 100755 => 100644 purify/resource/drive-harddisk.png mode change 100755 => 100644 purify/resource/folder.png mode change 100755 => 100644 purify/resource/input-gaming.png mode change 100755 => 100644 purify/resource/resource.cpp mode change 100755 => 100644 purify/resource/resource.hpp mode change 100755 => 100644 purify/resource/resource.xml mode change 100755 => 100644 purify/resource/view-refresh.png delete mode 100755 snesfilter/HQ2x/HQ2x-RGB555.cpp delete mode 100755 snesfilter/HQ2x/HQ2x.cpp delete mode 100755 snesfilter/LQ2x/LQ2x.cpp delete mode 100755 snesfilter/Makefile delete mode 100755 snesfilter/Phosphor3x/Phosphor3x.cpp delete mode 100755 snesfilter/Pixellate2x/Pixellate2x.cpp delete mode 100755 snesfilter/Scale2x/Scale2x.cpp delete mode 100755 snesfilter/Scanline/Scanline-Dark.cpp delete mode 100755 snesfilter/Scanline/Scanline-Light.cpp delete mode 100755 snesfilter/nall/array.hpp delete mode 100755 snesfilter/nall/bit.hpp delete mode 100755 snesfilter/nall/moduloarray.hpp delete mode 100755 snesfilter/nall/platform.hpp delete mode 100755 snesfilter/nall/reference_array.hpp delete mode 100755 snesfilter/nall/resource.hpp delete mode 100755 snesfilter/nall/snes/cartridge.hpp delete mode 100755 snesfilter/nall/snes/cpu.hpp delete mode 100755 snesfilter/nall/snes/smp.hpp delete mode 100755 snesfilter/nall/sort.hpp delete mode 100755 snesfilter/nall/stack.hpp delete mode 100755 snesfilter/nall/static.hpp delete mode 100755 snesfilter/nall/string/filename.hpp delete mode 100755 snesfilter/nall/string/math.hpp delete mode 100755 snesfilter/nall/string/platform.hpp delete mode 100755 snesfilter/nall/string/strl.hpp delete mode 100755 snesfilter/nall/test/cc.bat delete mode 100755 snesfilter/nall/test/cc.sh delete mode 100755 snesfilter/nall/test/document.bml delete mode 100755 snesfilter/nall/test/test delete mode 100755 snesfilter/nall/test/test.cpp delete mode 100755 snesfilter/nall/varint.hpp delete mode 100755 snesfilter/nall/vector.hpp delete mode 100644 snesfilter/out/.gitignore delete mode 100755 snesshader/Archive/HDR-TV.OpenGL.shader delete mode 100755 snesshader/Archive/Watercolor.OpenGL.shader delete mode 100755 snesshader/Curvature.OpenGL.shader delete mode 100755 snesshader/HQ2x.OpenGL.shader delete mode 100755 snesshader/Makefile delete mode 100755 snesshader/Pixellate.OpenGL.shader delete mode 100755 snesshader/Scale2x.OpenGL.shader delete mode 100755 snesshader/Sepia.Direct3D.shader diff --git a/bsnes/Makefile b/bsnes/Makefile old mode 100755 new mode 100644 index f1b70c6c..65ad25d5 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -4,11 +4,14 @@ fc := fc sfc := sfc gb := gb gba := gba +nds := nds profile := accuracy target := ethos -# options += console +# options += debugger +# arch := win32 +# console := true # compiler c := $(compiler) -std=gnu99 @@ -34,7 +37,15 @@ ifeq ($(platform),x) link += -ldl -lX11 -lXext else ifeq ($(platform),osx) else ifeq ($(platform),win) - link += $(if $(findstring console,$(options)),-mconsole,-mwindows) + ifeq ($(arch),win32) + flags += -m32 + link += -m32 + endif + ifeq ($(console),true) + link += -mconsole + else + link += -mwindows + endif link += -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32 link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc else @@ -94,7 +105,7 @@ sync: rm -r phoenix/test archive: - if [ -f bsnes.tar.bz2 ]; then rm bsnes.tar.bz2; fi - tar -cjf bsnes.tar.bz2 `ls` + if [ -f bsnes.tar.xz ]; then rm bsnes.tar.xz; fi + tar -cJf bsnes.tar.xz `ls` help:; diff --git a/bsnes/data/bsnes.Manifest b/bsnes/data/bsnes.Manifest old mode 100755 new mode 100644 diff --git a/bsnes/data/bsnes.desktop b/bsnes/data/bsnes.desktop old mode 100755 new mode 100644 diff --git a/bsnes/data/bsnes.ico b/bsnes/data/bsnes.ico old mode 100755 new mode 100644 diff --git a/bsnes/data/bsnes.png b/bsnes/data/bsnes.png old mode 100755 new mode 100644 diff --git a/bsnes/data/cheats.xml b/bsnes/data/cheats.xml old mode 100755 new mode 100644 index 0619442d..1f94df58 --- a/bsnes/data/cheats.xml +++ b/bsnes/data/cheats.xml @@ -1,5 +1,5 @@ - + 1942 (Japan, USA) @@ -423,6 +423,14 @@ Invincibility AVISVG + + One hit kills + EIKVVIEY + + + No enemies + GXUIZIAI + Addams Family, The (USA) @@ -3845,6 +3853,10 @@ Super fast punching AEUZITPA + + Force 2-player mode + AENTAIPL + Start with 1 life PENVZILA @@ -4383,6 +4395,13 @@ ZAXAYGAA + + Bio Miracle Bokutte Upa (Japan).nes + + Hit anywhere - normal enemies + AAKTZTIG+AEOLVGTZ + + Bionic Commando (USA) @@ -4417,10 +4436,30 @@ Autofire - main game XYXUUOEN + + Longer grapple line - sidescrolling levels + AINPTZAL+TSEOGZAG+YIVPAXZU + + + Longest grapple line - sidescrolling levels + EINPYZEP+EIVPPZEP+ESEOIZEP + + + Longer range for normal 3-way gun - sidescrolling levels + YOVUESPA + + + Longer range for fireball 3-way gun - sidescrolling levels + IPKLKVGA + Use with BIO Code 11 for improved autofire with normal gun AAKUOOZA + + Have all items (using the hidden gun will crash the game) + ELKLZAEY+EIXLTPEY + Start with 3 life energy capsules LAUKOZAA+XTUKUXVU @@ -9647,6 +9686,13 @@ PAUIEZIA + + Donkey Kong Jr. Math (USA, Europe).nes + + Always get the correct answer + AAKILSZA+AAUILSZP + + Donkey Kong Classics (USA, Europe) @@ -11273,6 +11319,10 @@ Infinite lives (alt) SGXGZGVG + + Multi-jump + ENVVIPNP+PXVVPOVP+XOVVTPXT+ZKVVGOGK + Take more damage APONPXAA @@ -13634,6 +13684,14 @@ Infinite credits SXXGSVVK + + Hit anywhere + AIUPKZEL+APUPSZGX+ASEOEPEL+EUEZTGGN+GKEZIKOS+KXEZYGIA+ZUEOOOAI + + + Get items from anywhere + AINPXZEL+YPNPUXPX + Galactic Crusader (USA) (Unl) @@ -15140,6 +15198,18 @@ Infinite special weapons SXVZTXSE + + One hit kills + EIEIYYEP + + + Enemies die automatically + AAUZLOAP+AUSSANAO+SAUZTOVK + + + Get items from anywhere + AUVSINKU+AVVSTNAP + Invincibility (alt) 0400:02 @@ -15546,6 +15616,13 @@ SLONNKSO + + Heracles no Eikou - Toujin Makyou Den (Japan) + + No random battles + AVSVTZAZ + + Hogan's Alley (World) @@ -17257,6 +17334,14 @@ Take less damage PTYSEK + + Hit anywhere + GKKEAZSK+OVKEPXPA+XEKEZZEP + + + Multi-jump + AEOTTIGA + 9 Tornado Attacks on pick-up PESIKYYE @@ -18643,6 +18728,14 @@ Press Start to complete the level GEXGUALU+LEXGSALU+OXXGXAIK + + Hit anywhere - throwing + ELXKKESZ+TIXKSAYA + + + Multi-jump when falling + ESXPZZEY+KOXPLZKS+OKOOYZOX+PEXPPXSG+PXXPAZES + One life after continue PASKOILA @@ -18889,6 +18982,14 @@ Infinite lives SXKTPKVG + + Hit anywhere (spitting) + AOOEIOOV+AOOETPYE+EANEZAAT+GGNEAESN+GXKEIPEL+VGNEPAGY + + + Inhale from anywhere + AASELZZG+AINEYZEP+SZNEGXSV + Less health from 'pep drinks' ZAKLLXAA @@ -18948,6 +19049,14 @@ Infinite lives SXKTPKVG + + Hit anywhere (spitting) + AEKAIEIA+AEXAIPTL+AOOAGEOV+AOOAIAYE+GXKEIPEL + + + Inhale from anywhere + AASELZZG+GXEAGZEL + Less health from 'pep drinks' ZAKLLXAA @@ -21342,6 +21451,10 @@ Magic of Scheherazade, The (USA) + + Invincibility + OXUYZKPX + Infinite HP OTSXLGSV @@ -21350,6 +21463,18 @@ Infinite lives SXEVPLVG + + Hit anywhere + AEEYYGLA+ALNNIGEP+SZNNLGSG+TZNNTKPA+UGNNGKPE + + + Never lose Mashroobs + SZEAEKVK + + + Get coins from anywhere + TEXAXLLA + Less energy gained from Bread POKAOZZU @@ -21358,10 +21483,6 @@ Less magic gained from Mashroobs ZAEEXGIA - - Never lose Mashroobs - SZEAEKVK - Start with only 20 Gold Coins ZAUTAZIA @@ -25957,6 +26078,13 @@ 03E2:1D + + Otaku no Seiza - An Adventure in the Otaku Galaxy (Japan) + + No random battles + AVEIXKOZ + + Over Horizon (Europe) @@ -27001,7 +27129,7 @@ - Princess Tomato in Salad Kingdom (USA) + Princess Tomato in the Salad Kingdom (USA) Infinite gold coins 03CB:09 @@ -29841,6 +29969,10 @@ Infinite time SZEVYZVG + + Hit anywhere + AKSZANEL+ATUILYEI+OXSZPNEX + 200 Machine Gun bullets on pick-up EKSTEAGV @@ -30578,6 +30710,13 @@ AANOLAZE + + Shinsenden (Japan) + + No random battles + ATXUPAAL + + Shooting Range (USA) @@ -33991,6 +34130,10 @@ Quick pick-up SXUASXOU + + Twice as much time in sub-space + NNXPZIAV + Infinite magic carpet time SLNZZLVI @@ -34194,6 +34337,10 @@ Quick pick-up SXUASXOU + + Twice as much time in sub-space + NNXPZIAV + Jump as high as a squat jump AEUEKKGL @@ -38384,6 +38531,10 @@ Vice - Project Doom (USA) + + Invincibility + AANSEIYP + Infinite lives SZSKIOVK @@ -38404,6 +38555,14 @@ Infinite power SXVYVKSE + + Hit anywhere + AEEYXEET + + + Multi-jump + XVVKISZK + 10 coins for an extra life ZEOYNGGV @@ -39101,10 +39260,22 @@ Wing of Madoola, The (Japan) (Sample) + + Invincibility + SXKGXTSA + Infinite hits and magic SLUUVYSP + + Hit anywhere + AAOGEVPA+AAOGSVZI+PZOGKTSN + + + One hit kills + APXKETSV+APXKOVEE + Start with 9999 hits OOKZKPAE+OOKXEPAO @@ -40490,6 +40661,17 @@ YYKSKIPE + + Ys III - Wanderers from Ys (Japan).nes + + Hit anywhere + XTKXSAAV+XTNXUAAV+XTVZKAAV+XVOZXAAV + + + One hit kills + AAEZYYGA + + Yume Koujou Doki Doki Panic (Japan) [b] (FDS) @@ -40567,6 +40749,10 @@ Zanac (USA) + + Invincibility + Hit anywhere + ALSEGZEU+ATSEIZPL+SZOELXOO + Infinite lives OXEENYVK @@ -42123,9 +42309,14 @@ Infinite lives DD67-4468 - - - DDB3-C764 + + Hit anywhere + 40B5-17A4+40B6-14A4+40BB-17D4+40BC-1DA4 + + + One hit kills + DDB3-C764 + Small magic power-up adds 3 instead of 1 D7C0-37A7 @@ -42923,6 +43114,14 @@ Infinite lives C282-34A1 + + Hit anywhere + DDA0-476A+DDA9-4F6A + + + Moon jump + 5C88-1D09+7D88-1DA9+DD83-17A9 + Adventures of Rocky and Bullwinkle and Friends, The (USA) @@ -44468,6 +44667,25 @@ 6D14-7DD4 + + Ashita no Joe (Japan) + + Hit anywhere - P1 + DD81-64AF + + + Hit anywhere - P2 + DD8A-A46D + + + Invincibility - P1 + 6D8A-6DDD + + + Invincibility - P2 + 6D81-0FDF + + Asterix (Europe) (En,Fr,De,Es) @@ -44775,6 +44993,10 @@ Infinite weapons (except for Flame) 3C37-A7D4 + + Hit anywhere + DDE2-6D04+DDEF-AD04 + Max weapons on pick-up DDC0-C770 @@ -46107,6 +46329,10 @@ Infinite Hyper Bombs - Neptune C2C3-DF67 + + Hit anywhere + 1D85-AD0F+1D8B-ADAF+C28A-D7A4+7685-ADDF+768B-AD6F + Start with 1 ship DD6E-6707 @@ -46178,6 +46404,10 @@ Infinite Discs 8289-CFDF + + Multi-jump + 6D21-CFAF+6D29-CD6F + Bobby's World (USA) (Proto) @@ -46186,13 +46416,25 @@ 2DB7-1DD8 - Infinite energy + Infinite health 82BC-1468 + + Infinite health (alt) + 7E139B03 + Infinite lives 822D-17AF + + Infinite lives (alt) + 7E139509 + + + Multi-jump + DDB3-17AC + Bonkers (USA) @@ -46216,6 +46458,10 @@ Infinite dash C98C-CD0F + + Hit anywhere + 6DE1-1F04+9DE1-1F64 + Boogerman - A Pick and Flick Adventure (USA) @@ -46286,6 +46532,14 @@ Boxing Legends of the Ring (USA) + + Invincibility - P1 + 6D6A-C4A9 + + + Invincibility - P2 + 6D66-3D05 + Infinite super punches - P1 C26D-3F05 @@ -46302,6 +46556,22 @@ Infinite time per round C2BA-A7A7 + + Hit anywhere - P1 + 1DBD-4460+F6BD-4400 + + + Hit anywhere - P2 + 1D69-3FD9+F669-3DA9 + + + Blocking disabled - P1 + DD62-CD09 + + + Blocking disabled - P2 + DD66-3FA5 + Each round is 1 minute DF8D-CDA7 @@ -48406,6 +48676,13 @@ D460-CD0D + + Bulls vs Blazers and the NBA Playoffs (USA) + + Never miss a shot + DD66-C4BD + + Bust-A-Move (USA) @@ -49569,6 +49846,14 @@ Infinite lives DDEC-CF6D + + Hit anywhere + DD6B-ADA4 + + + Multi-jump + DDA2-DDDF + Stay as Super Congo (you may change if you walk on spikes) CB69-34D7 @@ -50107,6 +50392,22 @@ Infinite Nutty attacks C287-34AD + + Hit anywhere + DD33-1DDF + + + Get items from anywhere + DD20-C7A4+DD26-1FD4+DD27-CFA7+DD3C-1D6D + + + One hit kills + 6D86-17DF + + + Disable recoil + DD89-CFAD + Juice cans set health to 1/2 D121-CD64 @@ -50774,6 +51075,14 @@ Invincibility after one hit C92A-44A7 + + Hit anywhere + DD66-47DC+DD6C-4D6C+6D6D-3DDC+6D64-3DAC + + + Get GP from anywhere + DDA5-176C + Large health refills full health C9AC-176C @@ -51490,6 +51799,10 @@ Infinite credits - both players C260-67F7 + + Hit and stomp anywhere + 6DAE-6469+F9AE-64A9 + Clock runs faster 7A64-D420 @@ -53648,9 +53961,17 @@ EE2E-54A1 - Fast money (buy a bread w/the code off, turn code on and sell it for $32,646) + Fast money (buy a bread with the code disabled, enable and sell it for $32,646) EE9A-E5F5 + + Dad never calls + E395-87DD + + + Massive numbers of enemies (piracy check) + 6D4F-7704 + Start with a level 9 character DB23-77D1 @@ -53683,10 +54004,6 @@ Start with a lot of PSI BB2F-54A1 - - Dad never calls - E395-87DD - Infinite health 7E9A13:E7+7E9A14:03 @@ -60503,8 +60820,16 @@ Imperium (USA) - Invincibility against lesser robots, weapons and lasers - 1D34-D4A1+1DC3-DDF7 + Invincibility + 6DCC-DD27+DD38-AFA9 + + + Hit anywhere + 6D31-DDA1+C236-DD01 + + + Infinite bombs + C2A9-D46F Start with 1 life point @@ -60683,6 +61008,18 @@ Health doesn't decrease when Hulked-out C260-4746 + + Hit anywhere + 0AB3-4D00+2DB3-4DD0+3DB2-4700+DDB2-4760+DDB2-47A0 + + + One hit kills + DDBF-47D0 + + + Get items from anywhere + 6DBF-17CB + Get 4 shots from gun D0BC-173B @@ -61373,6 +61710,13 @@ 7E0269:03 + + Jeopardy! (USA) + + Always get the correct answer + 6DC8-6D67+6DCE-64A7 + + Jetsons, The - Invasion of the Planet Pirates (USA) @@ -61499,6 +61843,10 @@ Hit anywhere 6DC3-0DAD+C9E5-DDDD+DDC4-076D + + One hit kills + 40CC-07DD + Start with 2 lives CBC8-6404+DFC8-6464 @@ -64516,10 +64864,9 @@ Pit death disabled 1DA9-04D1 - - Get 1 gold for each creature killed - 1BB5-D769+DFB5-D7A9+3CB6-DDD9 - + + + 1BB5-D769+DFB5-D7A9+3CB6-DDD9 Get 100 gold for each creature killed 1BB5-D769+10B5-D7A9+3CB6-DDD9 @@ -65106,6 +65453,10 @@ Dash without having the Pegasus Boots EEE5-2356 + + Dash without charge up + 45B8-D49A + Use the Magic Mirror to warp between the Light and Dark Worlds freely 6DC9-0D23 @@ -70208,6 +70559,10 @@ Infinite timeouts - both players (slightly glitchy) 8250-5700 + + Cannot be tackled (hold X) + 6D59-7FD7+7D59-7F67+C959-7DA7+DC59-7F07+E959-7FA7 + Field goals worth 0 points DD6F-8404 @@ -70283,6 +70638,10 @@ Infinite timeouts 8297-7F09 + + Cannot be tackled (hold X) + 6D6C-EFDF+7D6C-EF6F+C96C-EDAF+DC6C-EF0F+E96C-EFAF + Safeties are worth 0 points DD62-EFA7 @@ -70348,6 +70707,20 @@ DF65-E7A7 + + Madden NFL 97 (USA) + + Cannot be tackled (hold X) + 6D66-7767+7D6B-7DD7+C966-7707+DC66-77A7+E96B-7D07 + + + + Madden NFL 98 (USA) + + Cannot be tackled (hold X) + 6D6F-5407+7D6F-54A7+C96F-54D7+DC6F-5467+E96F-57D7 + + Magic Boy (USA) @@ -71254,7 +71627,7 @@ Infinite weapon energy - FEC2-E405 + FE42-E405 One hit kills @@ -71268,6 +71641,50 @@ Multi-jump DC51-ED65+BD51-EDA5+D751-EFD5+4D51-EF05+8551-EF65+7451-EFA5+4D51-E4D5+BC51-E405+FF51-E465+1D51-E4A5+1DFC-E400+5EFC-E460+C951-EDD5+0951-ED05 + + Always Shoot Shots + FF40-E405 + + + Always shoot Freeze Cracker + 4040-E405 + + + Always shoot Scorch Wheel + 4140-E405 + + + Always shoot Danger Wrap Bombs + 4340-E405 + + + Always shoot Noise Crush + 1140-E405 + + + Always shoot Fully Charged Mega Buster Blasts + 5240-E405 + + + Always shoot Slash Claw + BA40-E405 + + + Always shoot Thunder Bolt + 8940-E405 + + + Always shoot Wild Coil + E740-E405 + + + Always shoot Charged Wild Coils + EE40-E405 + + + White Shots/Special Weapons + EE02-E465 + Infinite E-Tanks (alt) 7E0BA0:FF @@ -71379,6 +71796,14 @@ Multi-jump 4065-17A9+EA66-1409+B966-1469 + + Enemies always drop large energy + C4CB-3DBD+D4CB-3D2D + + + Enemies always drop large weapon energy + C4CB-3DBD+D0CB-3D2D + Bogus jump (may go back to normal jumps) D08A-1FBC @@ -71482,6 +71907,14 @@ Multi-jump 4065-1F09+E465-17A9+B966-1DD9 + + Enemies always drop large energy + C4C6-379D+D4C6-37BD + + + Enemies always drop large weapon energy + C4C6-379D+D0C6-37BD + Bogus jump (may go back to normal jumps) D08A-1FBC @@ -71553,6 +71986,10 @@ Mega Man X2 (USA) + + Invincibility + D6B0-DD4F + Infinite health C223-0414 @@ -71573,10 +72010,6 @@ Multi-jump 40BE-DD44+26BE-D4C4+8BBE-D434 - - Invincibility - 8944008 - Infinite health (alt 2) 7E09FF:20 @@ -71680,6 +72113,14 @@ Multi-jump 4064-042F+D367-0F9F+C567-0FBF + + Enemies always drop large energy + C42E-0D2F+D42E-0FFF + + + Enemies always drop large weapon energy + C42E-0D2F+D02E-0FFF + Super-jump D586-6F26 @@ -71751,6 +72192,14 @@ View ending (select Capcom Championship) 81829B:EE+81829C:E0 + + Unlock Capcom Championship mode ending + 82D1F0:EA+82D1F1:EA+82D1F2:EA+82D1F3:EA + + + Unlock Tournament mode ending + 82D29C:EA+82D29D:EA+82D29E:EA+82D29F:EA + Metal Combat - Falcon's Revenge (USA) @@ -72097,6 +72546,10 @@ Infinite bombs on pick-up C2B7-0FF7 + + Collect items from anywhere + 4084-D794+6D8A-0724+F282-0DF4 + Mega-jump EC6A-ADF7 @@ -76654,6 +77107,10 @@ PGA Tour Golf (USA) + + Ball goes in from anywhere + 6D85-67AD+6DCC-ADD7 + Allow 14 clubs for full set instead of 13 D235-6D07+D22A-D40F @@ -78807,6 +79264,10 @@ Infinite lives - P2 3CB5-0467 + + Hit anywhere + 44E8-6446+6DE8-6F36+C9E3-6446 + Replacement planes carry 0 bombs - P1 CEB7-DFD7+62B7-DF07 @@ -79431,9 +79892,14 @@ No score lost when special attack is used DD62-A7A6 - - - EEC4-OD6F+EE64-646C+EE63-04A7+EE68-A7A1 + + Hit anywhere (might make some enemies invisible) + 6DB6-69EA+F9B6-617A + + + Start with more health + EEC4-OD6F+EE64-646C+EE63-04A7+EE68-A7A1 + Start with less health FEC4-0D6F+FE64-646C+FE63-04A7+FE68-A7A1 @@ -83080,9 +83546,14 @@ Infinite health C208-87D1 - - - FDDB-5FB9 + + Hit anywhere + 40F8-84B0 + + + Don't blink after getting hit + FDDB-5FB9 + Falling doesn't use life points C2F4-7FD1 @@ -87983,6 +88454,10 @@ Spin jump in mid air (hold for float down) F53F-6767+DD3F-67A7 + + Press R to scroll through items in the items box + D2AF-6407+D2AF-6DD7+DFAF-6F67+17AF-6FD7+1DAF-6467+62AF-6FA7+A4AD-67A7+A4AD-67D7+A4AF-64D7+CBAF-6F07+D1AF-6D67+D2AD-6707 + Low jump D02C-AF6F @@ -88500,6 +88975,10 @@ Infinite Power Bombs (alt) 17DA-9E8C + + Hit anywhere + 40C8-18DD+6DB1-3C6F+6DC2-1BDD + Super-jumps don't drain energy C22A-456D @@ -89717,6 +90196,28 @@ D4E9-6DEF + + Super Solitaire (USA) (En,Fr,De,Es,It) + + Move cards to any pile - Klondike + 6D8C-476F+DD8A-34AD+DD88-3D0D + + + Move cards to any pile - Free Cell + 6D8F-44A4 + + + + Super Soukoban (Japan) + + Infinite steps + C2CC-64AB + + + Walk through walls + DD88-D4A6+DD88-D706 + + Super Star Wars (USA) (Rev 1) @@ -91357,6 +91858,14 @@ Infinite hits on armor C2AA-0FAF + + Hit anywhere + DD8D-DD0D+DDAB-D4DF + + + Get items from anywhere + 6D8A-AF67 + Heart worth more F684-0F0D @@ -92158,6 +92667,13 @@ 3C38-C25D + + Tecmo Super NBA Basketball (USA) + + Never miss a shot (hold Y and press the shot button) + 7D69-CDE7+C269-CD77+D869-CD57+DC69-CD87+FF69-CF77 + + Teenage Mutant Ninja Turtles IV - Turtles in Time (USA) @@ -92371,6 +92887,26 @@ Start with 7 continues D6B1-CF60 + + Infinite health + 7E0EE460 + + + Full power bar + 7E1AC060 + + + Empty power bar - opponent + 7E1B1000 + + + Opponent dizzy after every knockdown + 7E0FC210 + + + Win one round to win match + 7E195002 + Tengai Makyou Zero (Japan) @@ -93198,6 +93734,18 @@ Race in any country 6DB7-AFEA + + Don't slow down offroad + C229-D4F1 + + + Don't slow down against obstacles + DD23-6499 + + + Don't slow down against cars + DD38-D7F9+DD38-DF29 + Start with 1/2 fuel 972B-0F64 @@ -97118,6 +97666,10 @@ Zero the Kamikaze Squirrel (USA) + + Jump higher + E060-1D62+E060-CF03 + Invincibility 7E0E2C:02 @@ -98947,6 +99499,25 @@ FA1-21E-4C1 + + Bubble Bobble (USA, Europe) + + Hit anywhere + 00D-22E-C4A+18D-29E-08A + + + Hit anywhere - Bosses (except final boss) + 00C-05B-A29+00B-FCB-A29 + + + Get items from anywhere + 00C-02D-A29+00C-0BD-A29+00D-56D-A29+375-8FB-6EE+37D-5FD-A29+C95-90B-91E + + + One hit kill - final boss + AF8-B7B-19E + + Bubble Bobble Part 2 (USA, Europe) @@ -99001,6 +99572,17 @@ BE6-00E-19E + + Bug's Life, A (USA) (SGB Enhanced) + + Infinite lives + 006-2FD-3BE + + + Invincibility (can still drown) + 000-EEE-081 + + BurgerTime Deluxe (World) @@ -99702,6 +100284,13 @@ 0AB-0C8-E6E + + Deer Hunter (USA) + + Infinite time + 004-1FF-19A + + Dig Dug (USA) @@ -100961,6 +101550,14 @@ Kid Icarus - Of Myths and Monsters (USA, Europe) + + Hit anywhere + 008-B8B-5D4 + + + Run into enemies to get Hearts + 185-67B-4CA + Collected hammers seem to count towards your enemy kill number C9A-D18-08F+7AA-B48-E69 @@ -101067,6 +101664,14 @@ Infinite vitality bars except against end of stage boss FA4-63B-4C1 + + Hit anywhere + 003-E1B-F7E + + + Inhale from anywhere + 008-53B-08E+008-67B-7FE + Start with 2 lives 021-BBF-F7E @@ -101114,6 +101719,18 @@ Infinite lives FA1-C4B-4C1 + + Hit anywhere + 006-E5D-6EA+187-04D-2AA + + + Inhale from anywhere + 005-BED-19E+005-DFD-91A + + + Get items from anywhere + 18B-898-08A + One hit and you die AFA-9EC-A28 @@ -102119,6 +102736,17 @@ 095-B2E-E66 + + Ms. Pac-Man (USA) + + Invincibility + 009-06E-E62 + + + Get fruit from anywhere + 00B-21E-D56 + + Mysterium (USA) @@ -102161,6 +102789,44 @@ 084-B5F-F7A + + Nemesis (Europe) + + Hit anywhere - Default weapon + 008-A7D-A29+008-B8D-A29 + + + Hit anywhere - Laser + 009-5FD-A29+009-70D-A29 + + + Hit anywhere - Missiles + 009-CBD-A29+009-DCD-A29 + + + Get items from anywhere + 007-68D-A29 + + + + Nemesis (USA) + + Hit anywhere - normal weapon + 008-A5D-A29+008-94D-A29 + + + Hit anywhere - Laser + 009-5DD-A29+009-4CD-A29 + + + Hit anywhere - Missiles + 009-C9D-A29+009-B8D-A29 + + + Get items from anywhere + 007-55D-A29 + + NFL Football (USA) @@ -102184,6 +102850,13 @@ 08F-59F-F72 + + Ninja Boy (USA, Europe) + + Hit anywhere (can get items from anywhere by punching) + 00E-279-C43 + + Nintendo World Cup (USA, Europe) @@ -102316,6 +102989,17 @@ 081-ACF-E66 + + Pac-Man (USA) + + Invincibility + C97-7DE-A29 + + + Get fruit from anywhere + 009-22E-E69+009-28E-E69 + + Pagemaster, The (USA) (SGB Enhanced) diff --git a/bsnes/data/laevateinn.hpp b/bsnes/data/laevateinn.hpp old mode 100755 new mode 100644 diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp old mode 100755 new mode 100644 index 0e83b052..b5e856aa --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -3,7 +3,7 @@ namespace Emulator { static const char Name[] = "bsnes"; - static const char Version[] = "089.18"; + static const char Version[] = "090"; static const char Author[] = "byuu"; static const char License[] = "GPLv3"; } diff --git a/bsnes/emulator/interface.hpp b/bsnes/emulator/interface.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/Makefile b/bsnes/fc/Makefile old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/apu.cpp b/bsnes/fc/apu/apu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/apu.hpp b/bsnes/fc/apu/apu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/dmc.cpp b/bsnes/fc/apu/dmc.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/dmc.hpp b/bsnes/fc/apu/dmc.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/envelope.cpp b/bsnes/fc/apu/envelope.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/envelope.hpp b/bsnes/fc/apu/envelope.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/noise.cpp b/bsnes/fc/apu/noise.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/noise.hpp b/bsnes/fc/apu/noise.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/pulse.cpp b/bsnes/fc/apu/pulse.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/pulse.hpp b/bsnes/fc/apu/pulse.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/serialization.cpp b/bsnes/fc/apu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/sweep.cpp b/bsnes/fc/apu/sweep.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/sweep.hpp b/bsnes/fc/apu/sweep.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/triangle.cpp b/bsnes/fc/apu/triangle.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/apu/triangle.hpp b/bsnes/fc/apu/triangle.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/bandai-fcg.cpp b/bsnes/fc/cartridge/board/bandai-fcg.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/board.cpp b/bsnes/fc/cartridge/board/board.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/board.hpp b/bsnes/fc/cartridge/board/board.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/konami-vrc1.cpp b/bsnes/fc/cartridge/board/konami-vrc1.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/konami-vrc2.cpp b/bsnes/fc/cartridge/board/konami-vrc2.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/konami-vrc3.cpp b/bsnes/fc/cartridge/board/konami-vrc3.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/konami-vrc4.cpp b/bsnes/fc/cartridge/board/konami-vrc4.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/konami-vrc6.cpp b/bsnes/fc/cartridge/board/konami-vrc6.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/konami-vrc7.cpp b/bsnes/fc/cartridge/board/konami-vrc7.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-axrom.cpp b/bsnes/fc/cartridge/board/nes-axrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-bnrom.cpp b/bsnes/fc/cartridge/board/nes-bnrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-cnrom.cpp b/bsnes/fc/cartridge/board/nes-cnrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-exrom.cpp b/bsnes/fc/cartridge/board/nes-exrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-fxrom.cpp b/bsnes/fc/cartridge/board/nes-fxrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-gxrom.cpp b/bsnes/fc/cartridge/board/nes-gxrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-hkrom.cpp b/bsnes/fc/cartridge/board/nes-hkrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-nrom.cpp b/bsnes/fc/cartridge/board/nes-nrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-pxrom.cpp b/bsnes/fc/cartridge/board/nes-pxrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-sxrom.cpp b/bsnes/fc/cartridge/board/nes-sxrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-txrom.cpp b/bsnes/fc/cartridge/board/nes-txrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/nes-uxrom.cpp b/bsnes/fc/cartridge/board/nes-uxrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/board/sunsoft-5b.cpp b/bsnes/fc/cartridge/board/sunsoft-5b.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/cartridge.cpp b/bsnes/fc/cartridge/cartridge.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/cartridge.hpp b/bsnes/fc/cartridge/cartridge.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/chip.cpp b/bsnes/fc/cartridge/chip/chip.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/chip.hpp b/bsnes/fc/cartridge/chip/chip.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/mmc1.cpp b/bsnes/fc/cartridge/chip/mmc1.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/mmc3.cpp b/bsnes/fc/cartridge/chip/mmc3.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/mmc5.cpp b/bsnes/fc/cartridge/chip/mmc5.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/mmc6.cpp b/bsnes/fc/cartridge/chip/mmc6.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/vrc1.cpp b/bsnes/fc/cartridge/chip/vrc1.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/vrc2.cpp b/bsnes/fc/cartridge/chip/vrc2.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/vrc3.cpp b/bsnes/fc/cartridge/chip/vrc3.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/vrc4.cpp b/bsnes/fc/cartridge/chip/vrc4.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/vrc6.cpp b/bsnes/fc/cartridge/chip/vrc6.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cartridge/chip/vrc7.cpp b/bsnes/fc/cartridge/chip/vrc7.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cheat/cheat.cpp b/bsnes/fc/cheat/cheat.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cheat/cheat.hpp b/bsnes/fc/cheat/cheat.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cpu/cpu.cpp b/bsnes/fc/cpu/cpu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cpu/cpu.hpp b/bsnes/fc/cpu/cpu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cpu/serialization.cpp b/bsnes/fc/cpu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/cpu/timing.cpp b/bsnes/fc/cpu/timing.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/fc.hpp b/bsnes/fc/fc.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/input/input.cpp b/bsnes/fc/input/input.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/input/input.hpp b/bsnes/fc/input/input.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/input/serialization.cpp b/bsnes/fc/input/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/interface/interface.cpp b/bsnes/fc/interface/interface.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/interface/interface.hpp b/bsnes/fc/interface/interface.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/memory/memory.cpp b/bsnes/fc/memory/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/memory/memory.hpp b/bsnes/fc/memory/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/ppu/ppu.cpp b/bsnes/fc/ppu/ppu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/ppu/ppu.hpp b/bsnes/fc/ppu/ppu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/ppu/serialization.cpp b/bsnes/fc/ppu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/scheduler/scheduler.cpp b/bsnes/fc/scheduler/scheduler.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/scheduler/scheduler.hpp b/bsnes/fc/scheduler/scheduler.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/system/serialization.cpp b/bsnes/fc/system/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/system/system.cpp b/bsnes/fc/system/system.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/system/system.hpp b/bsnes/fc/system/system.hpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/video/video.cpp b/bsnes/fc/video/video.cpp old mode 100755 new mode 100644 diff --git a/bsnes/fc/video/video.hpp b/bsnes/fc/video/video.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/Makefile b/bsnes/gb/Makefile old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/apu.cpp b/bsnes/gb/apu/apu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/apu.hpp b/bsnes/gb/apu/apu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/master/master.cpp b/bsnes/gb/apu/master/master.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/master/master.hpp b/bsnes/gb/apu/master/master.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/noise/noise.cpp b/bsnes/gb/apu/noise/noise.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/noise/noise.hpp b/bsnes/gb/apu/noise/noise.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/serialization.cpp b/bsnes/gb/apu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/square1/square1.cpp b/bsnes/gb/apu/square1/square1.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/square1/square1.hpp b/bsnes/gb/apu/square1/square1.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/square2/square2.cpp b/bsnes/gb/apu/square2/square2.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/square2/square2.hpp b/bsnes/gb/apu/square2/square2.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/wave/wave.cpp b/bsnes/gb/apu/wave/wave.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/apu/wave/wave.hpp b/bsnes/gb/apu/wave/wave.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/cartridge.cpp b/bsnes/gb/cartridge/cartridge.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/cartridge.hpp b/bsnes/gb/cartridge/cartridge.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/huc1/huc1.cpp b/bsnes/gb/cartridge/huc1/huc1.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/huc1/huc1.hpp b/bsnes/gb/cartridge/huc1/huc1.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/huc3/huc3.cpp b/bsnes/gb/cartridge/huc3/huc3.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/huc3/huc3.hpp b/bsnes/gb/cartridge/huc3/huc3.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mbc0/mbc0.cpp b/bsnes/gb/cartridge/mbc0/mbc0.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mbc0/mbc0.hpp b/bsnes/gb/cartridge/mbc0/mbc0.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mbc1/mbc1.cpp b/bsnes/gb/cartridge/mbc1/mbc1.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mbc1/mbc1.hpp b/bsnes/gb/cartridge/mbc1/mbc1.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mbc2/mbc2.cpp b/bsnes/gb/cartridge/mbc2/mbc2.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mbc2/mbc2.hpp b/bsnes/gb/cartridge/mbc2/mbc2.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mbc3/mbc3.cpp b/bsnes/gb/cartridge/mbc3/mbc3.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mbc3/mbc3.hpp b/bsnes/gb/cartridge/mbc3/mbc3.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mbc5/mbc5.cpp b/bsnes/gb/cartridge/mbc5/mbc5.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mbc5/mbc5.hpp b/bsnes/gb/cartridge/mbc5/mbc5.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mmm01/mmm01.cpp b/bsnes/gb/cartridge/mmm01/mmm01.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/mmm01/mmm01.hpp b/bsnes/gb/cartridge/mmm01/mmm01.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cartridge/serialization.cpp b/bsnes/gb/cartridge/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cheat/cheat.cpp b/bsnes/gb/cheat/cheat.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cheat/cheat.hpp b/bsnes/gb/cheat/cheat.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cpu/cpu.cpp b/bsnes/gb/cpu/cpu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cpu/cpu.hpp b/bsnes/gb/cpu/cpu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cpu/memory.cpp b/bsnes/gb/cpu/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cpu/mmio.cpp b/bsnes/gb/cpu/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cpu/serialization.cpp b/bsnes/gb/cpu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/cpu/timing.cpp b/bsnes/gb/cpu/timing.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/gb.hpp b/bsnes/gb/gb.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/interface/interface.cpp b/bsnes/gb/interface/interface.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/interface/interface.hpp b/bsnes/gb/interface/interface.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/memory/memory.cpp b/bsnes/gb/memory/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/memory/memory.hpp b/bsnes/gb/memory/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/ppu/cgb.cpp b/bsnes/gb/ppu/cgb.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/ppu/dmg.cpp b/bsnes/gb/ppu/dmg.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/ppu/mmio.cpp b/bsnes/gb/ppu/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/ppu/ppu.cpp b/bsnes/gb/ppu/ppu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/ppu/ppu.hpp b/bsnes/gb/ppu/ppu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/ppu/serialization.cpp b/bsnes/gb/ppu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/scheduler/scheduler.cpp b/bsnes/gb/scheduler/scheduler.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/scheduler/scheduler.hpp b/bsnes/gb/scheduler/scheduler.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/system/serialization.cpp b/bsnes/gb/system/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/system/system.cpp b/bsnes/gb/system/system.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/system/system.hpp b/bsnes/gb/system/system.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/video/video.cpp b/bsnes/gb/video/video.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gb/video/video.hpp b/bsnes/gb/video/video.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/Makefile b/bsnes/gba/Makefile old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/apu.cpp b/bsnes/gba/apu/apu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/apu.hpp b/bsnes/gba/apu/apu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/fifo.cpp b/bsnes/gba/apu/fifo.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/mmio.cpp b/bsnes/gba/apu/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/noise.cpp b/bsnes/gba/apu/noise.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/registers.cpp b/bsnes/gba/apu/registers.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/registers.hpp b/bsnes/gba/apu/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/sequencer.cpp b/bsnes/gba/apu/sequencer.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/serialization.cpp b/bsnes/gba/apu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/square.cpp b/bsnes/gba/apu/square.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/square1.cpp b/bsnes/gba/apu/square1.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/square2.cpp b/bsnes/gba/apu/square2.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/apu/wave.cpp b/bsnes/gba/apu/wave.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cartridge/cartridge.cpp b/bsnes/gba/cartridge/cartridge.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cartridge/cartridge.hpp b/bsnes/gba/cartridge/cartridge.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cartridge/eeprom.cpp b/bsnes/gba/cartridge/eeprom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cartridge/flashrom.cpp b/bsnes/gba/cartridge/flashrom.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cartridge/memory.hpp b/bsnes/gba/cartridge/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cartridge/serialization.cpp b/bsnes/gba/cartridge/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cpu/cpu.cpp b/bsnes/gba/cpu/cpu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cpu/cpu.hpp b/bsnes/gba/cpu/cpu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cpu/dma.cpp b/bsnes/gba/cpu/dma.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cpu/memory.cpp b/bsnes/gba/cpu/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cpu/mmio.cpp b/bsnes/gba/cpu/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cpu/registers.cpp b/bsnes/gba/cpu/registers.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cpu/registers.hpp b/bsnes/gba/cpu/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cpu/serialization.cpp b/bsnes/gba/cpu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cpu/state.hpp b/bsnes/gba/cpu/state.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/cpu/timer.cpp b/bsnes/gba/cpu/timer.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/gba.hpp b/bsnes/gba/gba.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/interface/interface.cpp b/bsnes/gba/interface/interface.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/interface/interface.hpp b/bsnes/gba/interface/interface.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/memory/memory.cpp b/bsnes/gba/memory/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/memory/memory.hpp b/bsnes/gba/memory/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/memory/mmio.cpp b/bsnes/gba/memory/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/memory/serialization.cpp b/bsnes/gba/memory/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/background.cpp b/bsnes/gba/ppu/background.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/memory.cpp b/bsnes/gba/ppu/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/mmio.cpp b/bsnes/gba/ppu/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/mosaic.cpp b/bsnes/gba/ppu/mosaic.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/object.cpp b/bsnes/gba/ppu/object.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/ppu.cpp b/bsnes/gba/ppu/ppu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/ppu.hpp b/bsnes/gba/ppu/ppu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/registers.cpp b/bsnes/gba/ppu/registers.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/registers.hpp b/bsnes/gba/ppu/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/screen.cpp b/bsnes/gba/ppu/screen.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/serialization.cpp b/bsnes/gba/ppu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/ppu/state.hpp b/bsnes/gba/ppu/state.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/scheduler/scheduler.cpp b/bsnes/gba/scheduler/scheduler.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/scheduler/scheduler.hpp b/bsnes/gba/scheduler/scheduler.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/system/bios.cpp b/bsnes/gba/system/bios.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/system/serialization.cpp b/bsnes/gba/system/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/system/system.cpp b/bsnes/gba/system/system.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/system/system.hpp b/bsnes/gba/system/system.hpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/video/video.cpp b/bsnes/gba/video/video.cpp old mode 100755 new mode 100644 diff --git a/bsnes/gba/video/video.hpp b/bsnes/gba/video/video.hpp old mode 100755 new mode 100644 diff --git a/bsnes/libco/amd64.c b/bsnes/libco/amd64.c old mode 100755 new mode 100644 diff --git a/bsnes/libco/fiber.c b/bsnes/libco/fiber.c old mode 100755 new mode 100644 diff --git a/bsnes/libco/libco.c b/bsnes/libco/libco.c old mode 100755 new mode 100644 diff --git a/bsnes/libco/libco.h b/bsnes/libco/libco.h old mode 100755 new mode 100644 diff --git a/bsnes/libco/ppc.c b/bsnes/libco/ppc.c old mode 100755 new mode 100644 diff --git a/bsnes/libco/sjlj.c b/bsnes/libco/sjlj.c old mode 100755 new mode 100644 diff --git a/bsnes/libco/ucontext.c b/bsnes/libco/ucontext.c old mode 100755 new mode 100644 diff --git a/bsnes/libco/x86.c b/bsnes/libco/x86.c old mode 100755 new mode 100644 diff --git a/bsnes/nall/Makefile b/bsnes/nall/Makefile old mode 100755 new mode 100644 diff --git a/bsnes/nall/algorithm.hpp b/bsnes/nall/algorithm.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/any.hpp b/bsnes/nall/any.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/atoi.hpp b/bsnes/nall/atoi.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/base64.hpp b/bsnes/nall/base64.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/bit.hpp b/bsnes/nall/bit.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/bmp.hpp b/bsnes/nall/bmp.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/bps/delta.hpp b/bsnes/nall/bps/delta.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/bps/linear.hpp b/bsnes/nall/bps/linear.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/bps/metadata.hpp b/bsnes/nall/bps/metadata.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/bps/patch.hpp b/bsnes/nall/bps/patch.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/compositor.hpp b/bsnes/nall/compositor.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/config.hpp b/bsnes/nall/config.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/crc32.hpp b/bsnes/nall/crc32.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/directory.hpp b/bsnes/nall/directory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dl.hpp b/bsnes/nall/dl.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp.hpp b/bsnes/nall/dsp.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp/buffer.hpp b/bsnes/nall/dsp/buffer.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp/core.hpp b/bsnes/nall/dsp/core.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp/resample/average.hpp b/bsnes/nall/dsp/resample/average.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp/resample/cosine.hpp b/bsnes/nall/dsp/resample/cosine.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp/resample/cubic.hpp b/bsnes/nall/dsp/resample/cubic.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp/resample/hermite.hpp b/bsnes/nall/dsp/resample/hermite.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp/resample/lib/sinc.hpp b/bsnes/nall/dsp/resample/lib/sinc.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp/resample/linear.hpp b/bsnes/nall/dsp/resample/linear.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp/resample/nearest.hpp b/bsnes/nall/dsp/resample/nearest.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp/resample/sinc.hpp b/bsnes/nall/dsp/resample/sinc.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/dsp/settings.hpp b/bsnes/nall/dsp/settings.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/emulation/famicom.hpp b/bsnes/nall/emulation/famicom.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/emulation/game-boy-advance.hpp b/bsnes/nall/emulation/game-boy-advance.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/emulation/game-boy.hpp b/bsnes/nall/emulation/game-boy.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/emulation/satellaview.hpp b/bsnes/nall/emulation/satellaview.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/emulation/sufami-turbo.hpp b/bsnes/nall/emulation/sufami-turbo.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/emulation/super-famicom-usart.hpp b/bsnes/nall/emulation/super-famicom-usart.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/emulation/super-famicom.hpp b/bsnes/nall/emulation/super-famicom.hpp old mode 100755 new mode 100644 index 597f9893..3115d7ea --- a/bsnes/nall/emulation/super-famicom.hpp +++ b/bsnes/nall/emulation/super-famicom.hpp @@ -106,6 +106,9 @@ struct SuperFamicomCartridge { }; SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) { + //skip copier header + if((size & 0x7fff) == 512) data += 512, size -= 512; + markup = ""; if(size < 0x8000) return; diff --git a/bsnes/nall/endian.hpp b/bsnes/nall/endian.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/file.hpp b/bsnes/nall/file.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/filemap.hpp b/bsnes/nall/filemap.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/function.hpp b/bsnes/nall/function.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/gzip.hpp b/bsnes/nall/gzip.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/http.hpp b/bsnes/nall/http.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/image.hpp b/bsnes/nall/image.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/inflate.hpp b/bsnes/nall/inflate.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/input.hpp b/bsnes/nall/input.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/interpolation.hpp b/bsnes/nall/interpolation.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/intrinsics.hpp b/bsnes/nall/intrinsics.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/invoke.hpp b/bsnes/nall/invoke.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/ips.hpp b/bsnes/nall/ips.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/lzss.hpp b/bsnes/nall/lzss.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/map.hpp b/bsnes/nall/map.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/mosaic.hpp b/bsnes/nall/mosaic.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/mosaic/bitstream.hpp b/bsnes/nall/mosaic/bitstream.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/mosaic/context.hpp b/bsnes/nall/mosaic/context.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/mosaic/parser.hpp b/bsnes/nall/mosaic/parser.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/nall.hpp b/bsnes/nall/nall.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/platform.hpp b/bsnes/nall/platform.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/png.hpp b/bsnes/nall/png.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/priority-queue.hpp b/bsnes/nall/priority-queue.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/property.hpp b/bsnes/nall/property.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/public-cast.hpp b/bsnes/nall/public-cast.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/random.hpp b/bsnes/nall/random.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/serial.hpp b/bsnes/nall/serial.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/serializer.hpp b/bsnes/nall/serializer.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/set.hpp b/bsnes/nall/set.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/sha256.hpp b/bsnes/nall/sha256.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/sort.hpp b/bsnes/nall/sort.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/stdint.hpp b/bsnes/nall/stdint.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/stream.hpp b/bsnes/nall/stream.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/stream/auto.hpp b/bsnes/nall/stream/auto.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/stream/file.hpp b/bsnes/nall/stream/file.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/stream/gzip.hpp b/bsnes/nall/stream/gzip.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/stream/http.hpp b/bsnes/nall/stream/http.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/stream/memory.hpp b/bsnes/nall/stream/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/stream/mmap.hpp b/bsnes/nall/stream/mmap.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/stream/stream.hpp b/bsnes/nall/stream/stream.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/stream/vector.hpp b/bsnes/nall/stream/vector.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/stream/zip.hpp b/bsnes/nall/stream/zip.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string.hpp b/bsnes/nall/string.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/base.hpp b/bsnes/nall/string/base.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/bml.hpp b/bsnes/nall/string/bml.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/bsv.hpp b/bsnes/nall/string/bsv.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/cast.hpp b/bsnes/nall/string/cast.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/compare.hpp b/bsnes/nall/string/compare.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/convert.hpp b/bsnes/nall/string/convert.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/core.hpp b/bsnes/nall/string/core.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/cstring.hpp b/bsnes/nall/string/cstring.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/filename.hpp b/bsnes/nall/string/filename.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/math-fixed-point.hpp b/bsnes/nall/string/math-fixed-point.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/math-floating-point.hpp b/bsnes/nall/string/math-floating-point.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/platform.hpp b/bsnes/nall/string/platform.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/replace.hpp b/bsnes/nall/string/replace.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/split.hpp b/bsnes/nall/string/split.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/static.hpp b/bsnes/nall/string/static.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/strm.hpp b/bsnes/nall/string/strm.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/strpos.hpp b/bsnes/nall/string/strpos.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/trim.hpp b/bsnes/nall/string/trim.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/utf8.hpp b/bsnes/nall/string/utf8.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/utility.hpp b/bsnes/nall/string/utility.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/variadic.hpp b/bsnes/nall/string/variadic.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/wildcard.hpp b/bsnes/nall/string/wildcard.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/wrapper.hpp b/bsnes/nall/string/wrapper.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/xml-legacy.hpp b/bsnes/nall/string/xml-legacy.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/string/xml.hpp b/bsnes/nall/string/xml.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/traits.hpp b/bsnes/nall/traits.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/udl.hpp b/bsnes/nall/udl.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/ups.hpp b/bsnes/nall/ups.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/utility.hpp b/bsnes/nall/utility.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/varint.hpp b/bsnes/nall/varint.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/vector.hpp b/bsnes/nall/vector.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/windows/detour.hpp b/bsnes/nall/windows/detour.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/windows/guid.hpp b/bsnes/nall/windows/guid.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/windows/launcher.hpp b/bsnes/nall/windows/launcher.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/windows/registry.hpp b/bsnes/nall/windows/registry.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/windows/utf8.hpp b/bsnes/nall/windows/utf8.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/xorg/guard.hpp b/bsnes/nall/xorg/guard.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/xorg/xorg.hpp b/bsnes/nall/xorg/xorg.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nall/zip.hpp b/bsnes/nall/zip.hpp old mode 100755 new mode 100644 diff --git a/bsnes/nds/Makefile b/bsnes/nds/Makefile new file mode 100644 index 00000000..43007231 --- /dev/null +++ b/bsnes/nds/Makefile @@ -0,0 +1,16 @@ +nds_objects := nds-interface +nds_objects += nds-cpu nds-apu nds-ppu nds-gpu nds-video +nds_objects += nds-memory nds-system nds-slot1 nds-slot2 nds-wifi +objects += $(nds_objects) + +obj/nds-interface.o: $(nds)/interface/interface.cpp $(call rwildcard,$(nds)/interface) +obj/nds-cpu.o: $(nds)/cpu/cpu.cpp $(call rwildcard,$(nds)/cpu) +obj/nds-apu.o: $(nds)/apu/apu.cpp $(call rwildcard,$(nds)/apu) +obj/nds-ppu.o: $(nds)/ppu/ppu.cpp $(call rwildcard,$(nds)/ppu) +obj/nds-gpu.o: $(nds)/gpu/gpu.cpp $(call rwildcard,$(nds)/gpu) +obj/nds-video.o: $(nds)/video/video.cpp $(call rwildcard,$(nds)/video) +obj/nds-memory.o: $(nds)/memory/memory.cpp $(call rwildcard,$(nds)/memory) +obj/nds-system.o: $(nds)/system/system.cpp $(call rwildcard,$(nds)/system) +obj/nds-slot1.o: $(nds)/slot1/slot1.cpp $(call rwildcard,$(nds)/slot1) +obj/nds-slot2.o: $(nds)/slot2/slot2.cpp $(call rwildcard,$(nds)/slot2) +obj/nds-wifi.o: $(nds)/wifi/wifi.cpp $(call rwildcard,$(nds)/wifi) \ No newline at end of file diff --git a/bsnes/nds/apu/apu.cpp b/bsnes/nds/apu/apu.cpp new file mode 100644 index 00000000..3e80d320 --- /dev/null +++ b/bsnes/nds/apu/apu.cpp @@ -0,0 +1,403 @@ +#include + +namespace NintendoDS { + +APU apu; + + +void APU::power() { + for(unsigned n = 0; n < 16; n++) { + auto &v = voices[n]; + + v.enable = false; + v.hold = false; + v.running = false; + v.format = Voice::PCM8; + v.duty = 0; + v.limit = 0; + v.panning = 0x40; + v.volumeBase = 0x7f; + v.volumeExp = 0; + v.amplitude = 0x7f0; + + v.source = 0; + v.length = 0; + v.counter = 0; + v.sample = 0; + + v.init.source = 0; + v.init.counter = 0; + v.init.length1 = 0; + v.init.length2 = 0; + + v.event.action = [&, n]() { stepVoice(n); }; + } + // Audio runs at 16.8MHz. I've somewhat arbitrarily set + // it up so that things run in the following order: + // - channel read + update (+0) + // - mixer (+1) + // - eventually, capture (+2) + // + // Mixer runs at 33Khz = 66 MHz / 2048 + mixEvent.action = [&]() { stepMixer(); }; + arm7.event.queue.add(2048+1, mixEvent); + + powered = true; +} + +void APU::stepMixer() { + arm7.event.queue.add(2048, mixEvent); + + int64 l = 0, r = 0; + + for(unsigned n = 0; n < 16; n++) { + auto &v = voices[n]; + int64 s = v.sample * v.amplitude; + + l += s * (128 - v.panning); + r += s * (0 + v.panning); + } + l = sclamp<16>(l / 0x80000); + r = sclamp<16>(r / 0x80000); + + interface->audioSample(l, r); +} + +void APU::stepVoice(unsigned no) { + auto &v = voices[no]; + + uint32 t = arm7.event.queue.time; + + if(v.format == Voice::PCM8) stepPCM8(no); + else if(v.format == Voice::PCM16) stepPCM16(no); + else if(v.format == Voice::ADPCM4) stepADPCM4(no); + else if(v.format == Voice::PSG && no >= 14) stepNoise(no); + else if(v.format == Voice::PSG && no >= 8) stepPulse(no); + + v.counter = v.init.counter; + + uint32 fetchTime = arm7.event.queue.time - t; + uint32 nextSample = 4*(0x10000 - v.counter); + + nextSample -= fetchTime; + if(unsigned k = t & 3) + nextSample += 4 - k; + + // When this happens, the buffering can't keep up. It isn't clear + // what the real system will do, but it can't be anything good... + if(nextSample >= 0x80000000) + nextSample = 0; + + // This requires further thought and investigation. + // Do buffering issues delay the playback timer? (hopefully not) + // Do audio DMAs interleave in any way? (doubtful; it'd be 10x slower) + if(v.running) + arm7.event.queue.add(nextSample, v.event); +} + +void APU::stepPulse(unsigned no) { + auto &v = voices[no]; + uint3 step = v.state--; + + v.sample = step > v.duty? -0x7fff : +0x7fff; +} + +void APU::stepNoise(unsigned no) { + auto &v = voices[no]; + bool out = v.state & 1; + + v.state >>= 1; + v.state ^= 0x6000*out; + v.sample = out? -0x7fff : +0x7fff; +} + +void APU::stepPCM8(unsigned no) { + auto &v = voices[no]; + + checkLength(no); + fillBuffer(no); + v.sample = 0x100*int8(v.buffer[v.index/8] >> 4*(v.index & 6)); + v.index += 2; + v.length -= 1; +} + +void APU::stepPCM16(unsigned no) { + auto &v = voices[no]; + + checkLength(no); + fillBuffer(no); + v.sample = int16(v.buffer[v.index/8] >> 4*(v.index & 4)); + v.index += 4; + v.length -= 2; +} + +void APU::stepADPCM4(unsigned no) { + auto &v = voices[no]; + + static const int16 table[] = { + 0x0007,0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e, + 0x0010,0x0011,0x0013,0x0015,0x0017,0x0019,0x001c,0x001f, + 0x0022,0x0025,0x0029,0x002d,0x0032,0x0037,0x003c,0x0042, + 0x0049,0x0050,0x0058,0x0061,0x006b,0x0076,0x0082,0x008f, + 0x009d,0x00ad,0x00be,0x00d1,0x00e6,0x00fd,0x0117,0x0133, + 0x0151,0x0173,0x0198,0x01c1,0x01ee,0x0220,0x0256,0x0292, + 0x02d4,0x031c,0x036c,0x03c3,0x0424,0x048e,0x0502,0x0583, + 0x0610,0x06ab,0x0756,0x0812,0x08e0,0x09c3,0x0abd,0x0bd0, + 0x0cff,0x0e4c,0x0fba,0x114c,0x1307,0x14ee,0x1706,0x1954, + 0x1bdc,0x1ea5,0x21b6,0x2515,0x28ca,0x2cdf,0x315b,0x364b, + 0x3bb9,0x41b2,0x4844,0x4f7e,0x5771,0x602f,0x69ce,0x7462, + 0x7fff + }; + + checkLength(no); + fillBuffer(no); + + if(v.state == 0x7fff) { + uint32 header = v.buffer[0]; + + // Minimum length is 4 words anyway, but check this later.. + v.sample = header>>0; + v.state = min(88, header>>16 & 0x7f); + v.index += 8; + v.length -= 4; + } + + int4 s = v.buffer[v.index/8] >> 4*(v.index & 7); + int16 x = table[v.state--]; + + int16 delta = x/8; + if(s & 1) delta += x/4; + if(s & 2) delta += x/2; + if(s & 4) delta += x/1, v.state += 2*(s & 3) + 3; + + if(s < 0) v.sample = max(-0x7fff, v.sample - delta); + else v.sample = min(+0x7fff, v.sample + delta); + + v.state = max(0, min(88, v.state)); + + if(++v.index & 1) return; + v.length -= 1; +} + + + +void APU::stopVoice(unsigned no) { + auto &v = voices[no]; + + arm7.event.queue.remove(v.event); + v.running = false; + if(v.hold == false) + v.sample = 0; +} + +void APU::fillBuffer(unsigned no) { + auto &v = voices[no]; + if(v.index) return; + + for(unsigned i = 0; i < 4; i++, v.source += 4) + v.buffer[i] = arm7.read(v.source, Word, true); +} + +void APU::checkLength(unsigned no) { + auto &v = voices[no]; + if(v.length) return; + + if(v.loop.source == 0xffffffff) { + // We're passing the loop point for the first time. In particular + // the hardware will store the ADPCM state. For this reason it's not + // possible to stream ADPCM audio without software assist. :( + v.length = v.loop.length; + v.loop.sample = v.sample; + v.loop.state = v.state; + v.loop.source = v.source; + if(v.index) // Account for buffer + v.loop.source += 4*(v.index/8 - 4); + + if(v.limit && v.length < 4) + return stopVoice(no); + } + else { + if(v.limit & Voice::once) + return stopVoice(no); + + // There are still issues with loops here.. or possibly + // readback of the voice status. + if(v.limit & Voice::looped) { + v.source = v.loop.source; + v.length = v.loop.length; + v.sample = v.loop.sample; + v.state = v.loop.state; + v.index = 0; + } + } +} + +void APU::checkEnable(unsigned no) { + auto &v = voices[no]; + + // maxmod's interpolated mode expects this undocumented behavior. Instead + // of software mixing, it resamples each voice's audio into a small buffer. + // Master enable is used to trigger every voice at the same time. + if(v.running == (enable && v.enable)) return; + + stopVoice(no); + v.running = enable && v.enable; + if(!v.running) return; + + uint32 next = 4*(0x10000 - v.init.counter); + + if(unsigned k = arm7.event.queue.time & 3) + next += 4 - k; // Align to 16MHz audio clock + + arm7.event.queue.add(next, v.event); + + // After 1 sample.. + v.length = 1; + v.event.action = [&, no]() { + uint32 period = 4*(0x10000 - v.init.counter); + + // Start the channel. From testing, it seems impossible to adjust + // length1/2 afterwards, so the settings must be latched somewhere. + // The loop flags can be changed though. + v.source = v.init.source; + v.counter = v.init.counter; + v.length = 4*v.init.length1; + v.loop.length = 4*v.init.length2; + v.loop.source = 0xffffffff; + v.sample = 0; + v.index = 0; + v.state = 0x7fff; + + // PCM has a couple more samples of startup latency. + // ADPCM takes a further 8 samples to process the header.. + switch(v.format) { + case Voice::PCM8: // add further startup latency + case Voice::PCM16: period = 3*period; break; + case Voice::ADPCM4: period = 11*period; break; + case Voice::PSG: period = 1*period; break; + } + + unsigned k = arm7.event.queue.time & 3; + if(k) period += 4 - k; + + arm7.event.queue.add(period, v.event); + v.event.action = [&, no]() { stepVoice(no); }; + }; +} + + +uint32 APU::regControl() { + return volume<<0 | output[0]<<8 | output[1]<<10 | muteDsp[0]<<12 | muteDsp[1]<<13 | enable<<15; +} + +uint32 APU::regBias() { + return bias; +} + +uint32 APU::regCaptureControl() { + return capture[0]<<7 | capture[1]<<15; +} + +uint32 APU::regCaptureDest(unsigned no) { + return captureDest[no]; +} + + + +void APU::regControl(uint32 data, uint32 mask) { + if(mask & 0x00ff) { + volume = data >> 0; + } + if(mask & 0xff00) { + output[0] = data >> 8; + output[1] = data >> 10; + muteDsp[0] = data >> 12; + muteDsp[1] = data >> 13; + enable = data >> 15; + + if(enable) { + // Start any pending voices - maxmod uses this for interpolated mode. + // What it does is: + // - clear the master enable + // - enable all 16 channels (won't do anything yet) + // - set the master enable (this will trigger all 16 at once) + // - wait ~16K clocks @ 33Mhz (16 samples), then set the mixing timer. + for(unsigned no = 0; no < 16; no++) + checkEnable(no); + } + } +} + +void APU::regBias(uint32 data, uint32 mask) { + bias = data; +} + +void APU::regCaptureControl(uint32 data, uint32 mask) { + capture[0] = data>>7; + capture[1] = data>>15; +} + +void APU::regCaptureDest(unsigned no, uint32 data, uint32 mask) { + captureDest[no] = data; +} + +void APU::regCaptureLength(unsigned no, uint32 data, uint32 mask) { + captureLength[no] = data; +} + + + +uint32 APU::regVoiceControl(unsigned no) { + auto &v = voices[no]; + + return v.volumeBase<<0 | v.volumeExp<<8 | v.hold<<15 | v.panning<<16 + | v.duty<<24 | v.limit<<27 | v.format<<29 | (v.running)<<31; +} + +void APU::regVoiceControl(unsigned no, uint32 data, uint32 mask) { + auto &v = voices[no]; + + int exponent[] = { 4, 3, 2, 0 }; + + if(mask & 0x0000007f) { + v.volumeBase = data >> 0; + v.amplitude = v.volumeBase << exponent[v.volumeExp]; + } + if(mask & 0x00008300) { + v.volumeExp = data >> 8; + v.hold = data >> 15; + v.amplitude = v.volumeBase << exponent[v.volumeExp]; + } + if(mask & 0x007f0000) { + v.panning = data >> 16; + } + if(mask & 0xff000000) { + v.duty = data >> 24; + v.limit = data >> 27; + v.format = data >> 29; + v.enable = data >> 31; + + checkEnable(no); + } +} + +void APU::regVoiceSource(unsigned no, uint32 data, uint32 mask) { + auto &v = voices[no]; + + v.init.source = data & 0x07fffffc; +} + +void APU::regVoicePeriod(unsigned no, uint32 data, uint32 mask) { + auto &v = voices[no]; + + if(mask & 0x0000ffff) v.init.counter ^= (v.init.counter ^ data>>0) & mask>>0; + if(mask & 0xffff0000) v.init.length1 ^= (v.init.length1 ^ data>>16) & mask>>16; +} + +void APU::regVoiceLength(unsigned no, uint32 data, uint32 mask) { + auto &v = voices[no]; + + v.init.length2 ^= (v.init.length2 ^ data) & mask & 0x3fffff; +} + +} diff --git a/bsnes/nds/apu/apu.hpp b/bsnes/nds/apu/apu.hpp new file mode 100644 index 00000000..7673fad7 --- /dev/null +++ b/bsnes/nds/apu/apu.hpp @@ -0,0 +1,100 @@ + +struct APU { + void power(); + + void stepMixer(); + + void stepVoice(unsigned no); + void stepPCM8(unsigned no); + void stepPCM16(unsigned no); + void stepADPCM4(unsigned no); + void stepPulse(unsigned no); + void stepNoise(unsigned no); + + void stopVoice(unsigned no); + void fillBuffer(unsigned no); + void checkLength(unsigned no); + void checkEnable(unsigned no); + + + uint32 regControl(); + uint32 regBias(); + uint32 regCaptureControl(); + uint32 regCaptureDest(unsigned no); + uint32 regVoiceControl(unsigned no); + + void regControl(uint32 data, uint32 mask); + void regBias(uint32 data, uint32 mask); + void regCaptureControl(uint32 data, uint32 mask); + void regCaptureDest(unsigned no, uint32 data, uint32 mask); + void regCaptureLength(unsigned no, uint32 data, uint32 mask); + + void regVoiceControl(unsigned no, uint32 data, uint32 mask); + void regVoiceSource(unsigned no, uint32 data, uint32 mask); + void regVoicePeriod(unsigned no, uint32 data, uint32 mask); + void regVoiceLength(unsigned no, uint32 data, uint32 mask); + + + + struct Voice { + uint1 enable, hold, running; + uint2 format; enum { PCM8, PCM16, ADPCM4, PSG }; + uint3 duty; + uint2 limit; enum { looped=1, once=2 }; + uint7 panning; + + // Volume is essentially some kind of float format. + // The effective value is base * 2^-(4 >> (3-exponent)). + uint7 volumeBase; + uint2 volumeExp; + + struct { + uint32 source; + uint16 counter; + uint16 length1; + uint32 length2; + } init; + + struct { + uint32 source; + uint32 length; + int16 sample; + int16 state; + } loop; + + uint32 source; + uint32 length; + uint16 counter; + + Event event; + + uint5 index; // nibble index into 16-byte buffer + uint32 buffer[4]; // holds 8, 16, or 32 buffered samples + int16 state; // used for pulse, noise, and ADPCM + + int32 amplitude; + int16 sample; + } voices[16]; + + Event mixEvent; + + // Voices 0 + 2 (L,R) are designated here as streaming audio. + // Voices 1 + 3 (L,R) are meant for DSP effects. Both are optional though. + uint1 powered; + uint1 enable; + uint10 bias; + uint7 volume; + uint2 output[2]; enum { srcMixer, srcDspL, srcDspR, srcDspMono }; + uint1 muteDsp[2]; // Don't send 1+3 to the mixer - avoids feedback. + uint1 dspToStream[3]; // Mix 1+3 back into 0+2. + + // Capture enables writing mixed audio to RAM - and in conjunction with + // voices 1 + 3, allows software DSP such as filtering or echo effects. + uint1 capture[2]; // Enable capturing + uint1 captureStream[2]; // ..otherwise mixer outputs + uint32 captureDest[2]; + uint32 captureLength[2]; + uint32 captureCount[2]; +}; + +extern APU apu; \ No newline at end of file diff --git a/bsnes/nds/cpu/arm.cpp b/bsnes/nds/cpu/arm.cpp new file mode 100644 index 00000000..d47eb0b3 --- /dev/null +++ b/bsnes/nds/cpu/arm.cpp @@ -0,0 +1,230 @@ + +void ARMCore::armWritePsr(uint1 opcode, uint4 mask, uint32 rm) { + r[15] += 4; + + if(opcode == 0) return writeCpsr(rm, mask); + if(opcode == 1) { + if(mode == USR || mode == SYS) return; + + uint32 update = 0xff000000*(mask>>3) | 0xff*(mask&1); + spsr() ^= (spsr() ^ rm) & update; + } +} + +void ARMCore::armReadPsr(uint1 opcode, uint4 ird) { + r[15] += 4; + + if(opcode == 0) r[ird] = readCpsr(); + if(opcode == 1) { + if(mode == USR || mode == SYS) return; + r[ird] = spsr(); + } + if(ird == 15) branch(0, r[15]); +} + +void ARMCore::armBranch(uint1 link, uint1 exch, int26 offset) { + if(link) r[14] = r[15] - 4; + branch(exch, r[15] + offset); +} + +void ARMCore::armBranchEx(uint1 link, uint4 irm) { + if(link) r[14] = r[15] - 4; + branch(r[irm] & 1, r[irm]); +} + +void ARMCore::armClz(uint4 ird, uint4 irm) { + auto &rd = r[ird], rm = r[irm]; + r[15] += 4; + + if(rm == 0) { rd = 32; return; } + + rd = 0; + while(~rm & 1<<31) + rm <<= 1, rd++; +} + +void ARMCore::armDspAdd(uint2 opcode, uint4 ird, uint4 irn, uint4 irm) { + auto &rd = r[ird], rn = r[irn], rm = r[irm]; + r[15] += 4; + + if(opcode & 2) { // qdadd/qdsub + rd = rm, rm += rm; + if(oflow(rm,rd,rd) & 1<<31) + Qf = -1, rm = 0x80000000 - (rm>>31); + } + if(opcode & 1) rd = rn - rm, (rm = ~rm); // qsub + else rd = rn + rm; // qadd + + if(oflow(rd,rn,rm) & 1<<31) + Qf = -1, rd = 0x80000000 - (rd>>31); + + if(ird == 15) branch(0, r[15]); +} + +void ARMCore::armDspMul(uint2 opcode, uint2 xy, uint4 ird, uint4 irn, uint4 irm, uint4 irs) { + auto rn = r[irn]; + r[15] += 4; + + if(opcode == 1) { // smulwy, smlawy + int32 rm = r[irm]; + int16 rs = r[irs] >> 16*(xy>>1); + uint32 rd = (int64) rm * rs >> 16; + + if(xy & 1) { + uint32 ra = rd + rn; + Qf |= oflow(ra,rd,rn); + rd = ra; + } + r[ird] = rd; + } + else { // smulxy(3), smlaxy(0), smlalxy(2) + int16 rm = r[irm] >> 16*(xy & 1); + int16 rs = r[irs] >> 16*(xy>>1); + int64 rd = (int64) rm * rs; + + if(opcode == 0) Qf |= oflow(rd+rn, rd, rn); // smlaxy + if(opcode != 3 /*accumulate*/) rd += rn; // smlaxy, smlalxy + if(opcode == 2 /*long*/) { + r[irn] = rd; rd >>= 32; + rd += r[ird]; + if(irn == 15) branch(0, r[15]); + } + r[ird] = rd; + } + if(ird == 15) branch(0, r[15]); +} + +void ARMCore::armMultiply(uint4 opcode, uint4 ird, uint4 irn, uint4 irm, uint4 irs) { + bool long_mul = opcode & 8, accumulate = opcode & 2; + bool signed_mul = opcode & 4, setf = opcode & 1; + + auto rm = r[irm], rs = r[irs], rn = r[irn]; + int64 rd = (uint64) rm * rs; + r[15] += 4; + + if(setf) Zf = 0; + if(accumulate) rd += rn; + if(long_mul) { + r[irn] = rd; rd >>= 32; + + if(setf) Zf |= r[irn]; + if(accumulate) rd += r[ird]; + if(signed_mul) { + if(rm & 1<<31) rd -= rs; + if(rs & 1<<31) rd -= rm; + } + } + r[ird] = rd; + if(setf) Nf = r[ird], Zf |= r[ird]; + if(ird == 15) branch(0, r[15]); +} + +void ARMCore::armData(uint5 opcode, uint4 ird, uint4 irn, SOut rm) { + auto rn = r[irn]; + r[15] += 4; + + alu(opcode, r[ird], rn, rm); + + if(ird == 15 && (opcode & 1)) writeCpsr(spsr(), 0xf); + if(ird == 15) branch(Tf, r[15]); // use Tf here because MOVS/SUBS changes it +} + +void ARMCore::armDataRs(uint5 opcode, uint4 ird, uint4 irn, uint4 irm, uint2 sh, uint4 irs) { + auto rs = r[irs]; + r[15] += 4; + + if(sh == 0) alu(opcode, r[ird], r[irn], lsl(r[irm], rs)); + if(sh == 1) alu(opcode, r[ird], r[irn], lsr(r[irm], rs)); + if(sh == 2) alu(opcode, r[ird], r[irn], asr(r[irm], rs)); + if(sh == 3) alu(opcode, r[ird], r[irn], ror(r[irm], rs)); + + if(ird == 15 && (opcode & 1)) writeCpsr(spsr(), 0xf); + if(ird == 15) branch(Tf, r[15]); +} + +void ARMCore::armMemSwap(uint1 opcode, uint4 ird, uint4 irn, uint4 irm) { + auto rn = r[irn]; + r[15] += 4; + + uint32 rd = load(rn, opcode? Byte : Word); + store(rn, opcode? Byte : Word, r[irm]); + r[ird] = rd; + if(ird == 15) branch(r[15] & 1, r[15]); +} + +void ARMCore::armMem(uint5 opcode, uint4 ird, uint4 irn, uint32 rm) { + auto &rd = r[ird], &rn = r[irn]; + uint32 update = opcode & 0x08? rn+rm : rn-rm; + uint32 addr = opcode & 0x10? update : rn; + r[15] += 4; + + if((opcode & 2) || !(opcode & 0x10)) rn = update; + + if(opcode & 1) rd = load(addr, opcode & 4? Byte : Word); // ldr, ldrb + else store(addr, opcode & 4? Byte : Word, rd); // str, strb + + if(ird == 15) branch(r[15] & 1, r[15]); +} + +void ARMCore::armMem_v4(uint5 opcode, uint2 sh, uint4 ird, uint4 irn, uint32 rm) { + auto &rd = r[ird], &rn = r[irn]; + uint32 update = opcode & 0x08? rn+rm : rn-rm; + uint32 addr = opcode & 0x10? update : rn; + r[15] += 4; + + if((opcode & 2) || !(opcode & 0x10)) rn = update; + + if(opcode & 1) { + if(sh == 1) rd = load(addr, Half); // ldrh + if(sh == 3) rd = (int16) load(addr, Half); // ldrsh + if(sh == 2) rd = (int8) load(addr, Byte); // ldrsb + if(ird == 15) branch(r[15] & 1, r[15]); + } else { + if(sh == 1) store(addr, Half, rd); // strh + } +} + +void ARMCore::armMem_v5(uint5 opcode, uint2 sh, uint4 ird, uint4 irn, uint32 rm) { + auto &rd = r[ird], &rn = r[irn]; + uint32 update = opcode & 0x08? rn+rm : rn-rm; + uint32 addr = opcode & 0x10? update : rn; + r[15] += 4; + + if((opcode & 2) || !(opcode & 0x10)) rn = update; + + if(~opcode & 1) { + if(sh == 3) { store(addr, Word, r[ird&~1]); store(addr+4, Word, r[ird|1]); } // strd + if(sh == 2) { r[ird&~1] = load(addr, Word); r[ird|1] = load(addr+4, Word); // ldrd + if(ird >= 14) branch(r[15] & 1, r[15]); } + } +} + +void ARMCore::armBlock(uint5 opcode, uint4 irn, uint16 rlist) { + unsigned index = opcode & 0x18, up = opcode & 0x08; + bool writeback = opcode & 0x02, ld = opcode & 0x01; + bool user = (opcode & 4) && !(ld && (rlist & 1<<15)); + auto &rn = r[irn]; + uint32 addr = rn, base = rn, size = 4*bit::count(rlist); + r[15] += 4; + + if(index == 0x00) addr += 4 - size; // da + if(index == 0x10) addr += 0 - size; // db + if(index == 0x18) addr += 4; // ib + + if(user) swapBank(mode); + + for(unsigned b = 0, s = 0; b < 16; b++) { + if(~rlist & 1<= 0; j--) + crc = crc>>1 ^ (crc&1) * (table[j] << j); + } + return crc; +} + +void ARM7TDMI::main() { + if(auto card = slot1.card) { + // ARM7 BIOS and firmware should be doing this, but it requires + // clock, card emulation and fancy things like that. + uint32 arm9src = card->rom.read(0x20, Word), arm7src = card->rom.read(0x30, Word); + uint32 arm9entry = card->rom.read(0x24, Word), arm7entry = card->rom.read(0x34, Word); + uint32 arm9dest = card->rom.read(0x28, Word), arm7dest = card->rom.read(0x38, Word); + uint32 arm9size = card->rom.read(0x2c, Word), arm7size = card->rom.read(0x3c, Word); + + // Copy user settings to RAM + // - Homebrew and games (?) both require this. libnds actually attempts + // to read the settings from flash, but the struct contains a bitfield + // that GCC expands by 2 bytes, throwing the size and checksum off. + for(unsigned n = 0; n < 0x70; n += 1) { + store(0x02fffc80+n, Byte, system.firmware.read(0x3fe00+n, Byte)); + } + + // Check CRCs on firmware data and warn if incorrect + uint8 *wifiData = &system.firmware.data[0x0002a]; + + uint8 *wfcData[3] = { + &system.firmware.data[0x3fa00], + &system.firmware.data[0x3fb00], + &system.firmware.data[0x3fc00], + }; + uint8 *userData[2] = { + &system.firmware.data[0x3fe00], + &system.firmware.data[0x3ff00], + }; + + // MAC address + Wifi chipset programming data + uint32 wifiDataLen = wifiData[2] | wifiData[3]<<8; + uint32 wifiDataExpected = wifiData[0] | wifiData[1]<<8; + uint32 wifiDataActual = crc16(wifiData+2, wifiDataLen, 0); + + if(wifiDataExpected != wifiDataActual) + print("Warning: Wifi chipset data: crc is ", + hex<4>(wifiDataActual),"; expected ",hex<4>(wifiDataExpected),"\n"); + + // Nintendo Wifi Connection - access point IDs + WEP passwords + for(unsigned i = 0; i < 3; i++) { + uint32 expected = wfcData[i][0xfe] | wfcData[i][0xff]<<8; + uint32 actual = crc16(wfcData[i], 0xfe, 0); + + if(expected != actual) + print("Warning: WFC access point #",i,": crc is ", + hex<4>(actual),"; expected ",hex<4>(expected),"\n"); + } + + // User settings area - nickname, birthday, favorite color etc. + for(unsigned i = 0; i < 2; i++) { + uint32 expected = userData[i][0x72] | userData[i][0x73]<<8; + uint32 actual = crc16(userData[i], 0x70, 0xffff); + + if(expected != actual) + print("Warning: User settings #",i,": crc is ", + hex<4>(actual),"; expected ",hex<4>(expected),"\n"); + } + + // Copy header into RAM + for(unsigned n = 0; n < 0x200; n += 4) { + write(0x02fffe00+n, Word, 0, card->rom.read(n, Word)); + } + + // Copy executables + if(0x200 <= arm9src && arm9src + arm9size <= card->rom.size) { + if(0x02000000 <= arm9dest && arm9dest + arm9size <= 0x023bfe00) { + for(unsigned n = 0; n < arm9size; n += 4) + write(arm9dest + n, Word, 0, card->rom.read(arm9src + n, Word)); + } + } + if(0x200 <= arm7src && arm7src + arm7size <= card->rom.size) { + if(0x02000000 <= arm7dest && arm7dest + arm7size <= 0x023bfe00 + || 0x037f8000 <= arm7dest && arm7dest + arm7size <= 0x03807e00) { + for(unsigned n = 0; n < arm7size; n += 4) + write(arm7dest + n, Word, 0, card->rom.read(arm7src + n, Word)); + } + } + // Should write the card's ROM ID to RAM too... where is it again? + arm7.booted = 0; + arm9.booted = 0; + + arm7.writeCpsr(0xdf, 0xf); + arm7.branch(arm7entry & 1, arm7entry); + arm7.r[15] = arm7entry; // pc + arm7.r[14] = arm7entry; // lr + arm7.r[13] = 0x03007f00; // sp + arm7.r_irq[0] = 0x03007fa0; // sp_irq + arm7.r_svc[0] = 0x03007fe0; // sp_svc + + arm9.writeCpsr(0xdf, 0xf); + arm9.branch(arm9entry & 1, arm9entry); + arm9.r[15] = arm9entry; // pc + arm9.r[14] = arm9entry; // lr + arm9.r[13] = 0x00803ec0; // sp + arm9.r_irq[0] = 0x00803fa0; // sp_irq + arm9.r_svc[0] = 0x00803fc0; // sp_svc + } + + arm7.event.queue.time -= arm7.clock; + for(unsigned n=1; n <= arm7.event.queue.size; n++) + arm7.event.queue.items[n]->time -= arm7.clock; + + arm7.clock = 0; + + for(;;) { + if(arm7.clock >= 256) + co_switch(arm9.thread); + + event.irq = interrupt.gate && (interrupt.enable & interrupt.flags); + //if(event.irq && !If) { + // print("arm7: irq (if=",hex<8>(interrupt.flags),")\n"); + //} + + if(Tf) execTHUMB(); + else execARM(); + } +} + +void ARM7TDMI::istep(unsigned clocks) { + arm7.clock += 2*clocks; + event.queue.step(2*clocks); +} + +void ARM7TDMI::step(unsigned clocks) { + return istep(clocks); +} + + + +void ARM7TDMI::execARM() { + if(branched) { + //if(r[15] == 0) print(hex<8>(r[14]), ": jump to nullptr!\n"); + branched = false; r[15] &= ~3; + iexecute = fetch(r[15], Word, 0); r[15] += 4; + idecode = fetch(r[15], Word, 1); r[15] += 4; + } else { + iexecute = idecode, idecode = ifetch; + } + ifetch = fetch(r[15], Word, 1); + uint32 i = iexecute; + + if(event.irq && !If) return irq(); + //if(trace && r[15] >= 0x2000000) traceInsn(); + + if(!evalCond(i>>28)) { r[15] += 4; return; } + + // opcode, sh, Rd, Rn, Rm, Rs + if(imatch("00x10xx0/////")) { + if(imatch("00110r10/// ..../")) return armWritePsr(i>>22, i>>16, armImmed(i, i>>8)); + if(imatch("00010r10/// 0000/")) return armWritePsr(i>>22, i>>16, armRm(i)); + if(imatch("00010r00/// 0000/")) return armReadPsr (i>>22, i>>12); + if(imatch("00010010/// 00l1/")) return armBranchEx( i>>5, i); + if(imatch("00010b00/// 1001/")) return armMemSwap (i>>22, i>>12, i>>16, i); + } + if(imatch("000...../// 1..1/")) { + if(imatch("0000luas/// 1001/")) return armMultiply(i>>20, i>>16, i>>12, i, i>>8); + if(imatch("000pu0wl/// 1sh1/")) return armMem_v4 (i>>20, i>>5, i>>12, i>>16, armRm(i)); + if(imatch("000pu1wl/// 1sh1/")) return armMem_v4 (i>>20, i>>5, i>>12, i>>16, armOffset8(i, i>>8)); + } + if(imatch("001aaaas/// ..../")) return armData (i>>20, i>>12, i>>16, armImmed(i, i>>8)); + if(imatch("000aaaas/// .sh0/")) return armData (i>>20, i>>12, i>>16, shiftImm(i, i>>5, i>>7)); + if(imatch("010pubwl/// ..../")) return armMem (i>>20, i>>12, i>>16, armOffset12(i)); + if(imatch("011pubwl/// ...0/")) return armMem (i>>20, i>>12, i>>16, shiftImm(i, i>>5, i>>7)); + if(imatch("100puswl/// ..../")) return armBlock (i>>20, i>>16, i); + if(imatch("101l..../// ..../")) return armBranch (i>>24, 0, i<<2); + if(imatch("000aaaas/// 0sh1/")) return armDataRs (i>>20, i>>12, i>>16, i, i>>5, i>>8); + + if(imatch("1111..../// ..../")) return swi (); + return undefined(); +} + +void ARM7TDMI::execTHUMB() { + if(branched) { + //if(r[15] == 0) print(hex<8>(r[14]), ": jump to nullptr!\n"); + branched = false; r[15] &= ~1; + iexecute = fetch(r[15], Half, 0) >> 8*(r[15] & 2) & 0xffff; r[15] += 2; + idecode = fetch(r[15], Half, 1) >> 8*(r[15] & 2) & 0xffff; r[15] += 2; + } else { + iexecute = idecode, idecode = ifetch; + } + ifetch = fetch(r[15], Half, 1) >> 8*(r[15] & 2) & 0xffff; + uint16 i = iexecute; + + if(event.irq && !If) return irq(); + //if(trace && r[15] >= 0x2000000) traceInsn(); + + if(imatch("00011ismmmnnnddd")) return thumbAddSub (i>>9, i, i>>3, i>>6); + if(imatch("000ssiiiiimmmddd")) return thumbShiftImm(i>>11, i, i>>3, i>>6); + if(imatch("001oodddiiiiiiii")) return thumbDataImm (i>>11, i>>8, i); + if(imatch("010000oooommmddd")) return thumbDataLo (i>>6, i, i>>3); + if(imatch("010001oodmmmmddd")) return thumbDataHi (i>>8, (i&7)+(i>>4&8), i>>3); + + if(imatch("0101ooommmnnnddd")) return thumbMemReg (i>>9, i, i>>3, i>>6); + if(imatch("011bliiiiinnnddd")) return thumbMemImm (i>>11, i, i>>3, i>>6); + if(imatch("1000liiiiinnnddd")) return thumbMemImm (i>>11, i, i>>3, i>>6); + + if(imatch("10110000siiiiiii")) return thumbAddSP ( i>>7, i); + if(imatch("01001dddrrrrrrrr")) return thumbRelative(i>>11, i>>8, i); + if(imatch("1001odddrrrrrrrr")) return thumbRelative(i>>11, i>>8, i); + if(imatch("1010odddrrrrrrrr")) return thumbRelative(i>>11, i>>8, i); + + if(imatch("1101ccccrrrrrrrr")) return thumbCond ( i>>8, i); + if(imatch("11100rrrrrrrrrrr")) return thumbBranch (i); + if(imatch("11110rrrrrrrrrrr")) return thumbBh (i); + if(imatch("11111rrrrrrrrrrr")) return thumbBlx (1, i); + + if(imatch("1o..lnnnrrrrrrrr")) return thumbBlock (i>>11, i>>8, i); + + return undefined(); +} + + + +uint32 ARM7TDMI::fetch(uint32 addr, uint32 size, bool s) { + return read(addr, size, s); +} + +uint32 ARM7TDMI::read(uint32 addr, uint32 size, bool s) { + const int h = size==Word? 2 : 1; // 16-bit bus timing + const int e = 8*!s + h; // EWRAM timing + + //if((addr & 0xf3ff000) == 0x23ff000) { + // istep(e); + // uint32 data = system.ewram.read(addr % 0x400000, size); + // print(hex<8>(arm7.event.queue.time), " ",hex<8>(r[15])," arm7: r ",hex<8>(addr),":",size," = ",hex<8>(data),"\n"); + // return data; + //} + + switch(addr >> 23) { + case 0x00>>3: + case 0x08>>3: istep(1); addr &= bios.size-1; return bios.read(addr, size); + case 0x20>>3: + case 0x28>>3: istep(e); addr %= 0x400000; return system.ewram.read(addr, size); + case 0x30>>3: istep(1); addr %= 0x008000; return system.swram[addr>>14].read(addr % 0x4000, size); + case 0x38>>3: istep(1); addr %= 0x010000; return system.iwram.read(addr, size); + case 0x40>>3: istep(1); { // return readReg(addr, size); + uint32 data = readReg(addr, size); + //print(hex<8>(arm7.event.queue.time), " ", hex<8>(r[15])," arm7: r ",hex<8>(addr),":",size," = ",hex<8>(data),"\n"); + return data; + } + case 0x48>>3: istep(1); return wifi.read(addr, size); + case 0x60>>3: + case 0x68>>3: istep(h); addr %= 0x040000; return system.vmap.arm7[addr>>14].read(addr, size); + } + istep(1); + return 0; +} + +void ARM7TDMI::write(uint32 addr, uint32 size, bool s, uint32 data) { + const int h = size==Word? 2 : 1; // 16-bit bus timing + const int e = 8*!s + h; // EWRAM timing + + //if((addr & 0xf3ff000) == 0x23ff000) + // print(hex<8>(arm7.event.queue.time), " ",hex<8>(r[15]), " arm7: w ",hex<8>(addr),":",size," = ",hex<8>(data),"\n"); + + switch(addr >> 23) { + case 0x20>>3: + case 0x28>>3: istep(e); addr %= 0x400000; return system.ewram.write(addr, size, data); + case 0x30>>3: istep(1); addr %= 0x008000; return system.swram[addr>>14].write(addr % 0x4000, size, data); + case 0x38>>3: istep(1); addr %= 0x010000; return system.iwram.write(addr, size, data); + case 0x40>>3: istep(1); { // return writeReg(addr, size, data); + //if(addr != 0x4000301) + // print(hex<8>(arm7.event.queue.time), " ", hex<8>(r[15])," arm7: w ",hex<8>(addr),":",size," = ",hex<8>(data),"\n"); + writeReg(addr, size, data); + return; + } + case 0x48>>3: istep(1); return wifi.write(addr, size, data); + case 0x60>>3: + case 0x68>>3: istep(h); addr %= 0x040000; if(size > Byte) return system.vmap.arm7[addr>>14].write(addr, size, data); + // STRB - special case, only works on ARM7 + auto &page = system.vmap.arm7[addr>>14]; + page[addr] &= addr & 1? 0x00ff : 0xff00; + page[addr] |= addr & 1? data & 0xff00 : data & 0x00ff; + return; + } + istep(1); +} + +void ARM7TDMI::dataCop(uint4 cpno, uint4 op1, uint4 ird, uint4 irn, uint4 irm, uint4 op2) { + return undefined(); +} + + + +uint32 ARM7TDMI::readReg(uint32 addr, uint32 size) { + switch(addr-0x4000000 & ~3) { + + case 0x134: { + // Aux GPIO + // - missing link port (SI pin = clock /IRQ) + // - misc inputs + uint8 keys = 0; + for(unsigned n = 10; n < 16; n++) { + if(interface->inputPoll(ID::Port::Buttons, 0, n)) + keys += 1 << n-10; + } + if(system.touchscreen.penDown()) keys += 1<<6; + if(interface->inputPoll(ID::Port::Sensors, 0, ID::Sensors::Lid)==0) keys += 1<<7; + return (keys ^ 0xff)<<16 | regSio()<<0; + } + + case 0x138: return regRtc(); // GPIO - system clock + case 0x1c0: return regSpi(); // SPI - power, touch, firmware flash + + // Memory status, slot 2 + case 0x204: return arm9.ramPriority<<15 | arm9.slot1access<<11 + | arm9.slot2access<< 7 | regSlot2Control(); + // Wifi waitstates + case 0x206: break; + + case 0x240: break; // VRAM status + case 0x241: break; // SWRAM status + + case 0x300: return flag300<<1 | booted<<0; + case 0x304: return apu.powered<<0 | wifi.powered<<1; + + case 0x400: case 0x410: case 0x420: case 0x430: + case 0x440: case 0x450: case 0x460: case 0x470: + case 0x480: case 0x490: case 0x4a0: case 0x4b0: + case 0x4c0: case 0x4d0: case 0x4e0: case 0x4f0: + return apu.regVoiceControl(addr>>4 & 15); + + case 0x500: return apu.regControl(); + case 0x504: return apu.regBias(); + case 0x508: return apu.regCaptureControl(); + case 0x510: return apu.regCaptureDest(0); + case 0x518: return apu.regCaptureDest(1); + + } + return CPUCore::readReg(addr, size); +} + +void ARM7TDMI::writeReg(uint32 addr, uint32 size, uint32 data) { + uint32 mask = 0xffffffff; + if(size == Half) mask = 0xffff << 8*(addr & 2); + if(size == Byte) mask = 0xff << 8*(addr & 3); + + data &= mask; + + switch(addr-0x4000000 & ~3) { + + case 0x134: return regSio(data, mask); // GPIO - missing link port + case 0x138: return regRtc(data, mask); // GPIO - system clock + case 0x1c0: return regSpi(data, mask); // SPI - power, touch, firmware flash + + case 0x204: return regSlot2Control(data, mask); + case 0x206: break; // Wifi waitstates + + case 0x300: // System mode + booted |= data & 1; // not possible to clear it + if(mask & 0xff) + flag300 = data >> 1; + + // 0x4000: halt arm9 and enter GBA mode + // 0x8000: halt arm7 and wait for IRQ + // 0xc000: halt system and wait for IRQ (low-power sleep mode) + // + // Nearly everything is frozen in sleep mode, including timers. Only + // a few things can generate interrupts to bring it back out: + // - lid sensor, buttons + // - alarm from real-time clock + // - wireless chipset (?) + // - cart in slot 1 or 2 (?) + if(data & 0xc000) { + //print("arm7: wait (ime=",interrupt.gate,", ie=",hex<8>(interrupt.enable),")\n"); + powerState = waiting; + for(;;) { + if((interrupt.enable & interrupt.flags)) { + powerState = running; + break; + } + istep(256); + if(arm7.clock >= 256) + co_switch(arm9.thread); + } + } + return; + + case 0x304: // Power + if(mask & 0xff) { + apu.powered = data>>0; + wifi.powered = data>>1; + } + return; + + case 0x308: break; // BIOS protection + + case 0x400: case 0x410: case 0x420: case 0x430: + case 0x440: case 0x450: case 0x460: case 0x470: + case 0x480: case 0x490: case 0x4a0: case 0x4b0: + case 0x4c0: case 0x4d0: case 0x4e0: case 0x4f0: + return apu.regVoiceControl(addr>>4 & 15, data, mask); + + case 0x404: case 0x414: case 0x424: case 0x434: + case 0x444: case 0x454: case 0x464: case 0x474: + case 0x484: case 0x494: case 0x4a4: case 0x4b4: + case 0x4c4: case 0x4d4: case 0x4e4: case 0x4f4: + return apu.regVoiceSource(addr>>4 & 15, data, mask); + + case 0x408: case 0x418: case 0x428: case 0x438: + case 0x448: case 0x458: case 0x468: case 0x478: + case 0x488: case 0x498: case 0x4a8: case 0x4b8: + case 0x4c8: case 0x4d8: case 0x4e8: case 0x4f8: + return apu.regVoicePeriod(addr>>4 & 15, data, mask); + + case 0x40c: case 0x41c: case 0x42c: case 0x43c: + case 0x44c: case 0x45c: case 0x46c: case 0x47c: + case 0x48c: case 0x49c: case 0x4ac: case 0x4bc: + case 0x4cc: case 0x4dc: case 0x4ec: case 0x4fc: + return apu.regVoiceLength(addr>>4 & 15, data, mask); + + case 0x500: return apu.regControl(data, mask); + case 0x504: return apu.regBias(data, mask); + case 0x508: return apu.regCaptureControl(data, mask); + case 0x510: return apu.regCaptureDest(0, data, mask); + case 0x514: return apu.regCaptureLength(0, data, mask); + case 0x518: return apu.regCaptureDest(1, data, mask); + case 0x51c: return apu.regCaptureLength(1, data, mask); + + } + return CPUCore::writeReg(addr, size, data); +} + + +uint32 ARM7TDMI::regSpi() { + return spi.divider<<0 | spi.device<<8 | spi.size<<10 + | spi.hold<<11 | spi.irq<<14 | spi.enable<<15 + | spi.data<<16; +} + +void ARM7TDMI::regSpi(uint32 data, uint32 mask) { + if(mask & 0x000000ff) { + spi.divider = data>>0; + } + if(mask & 0x0000ff00) { + spi.device = data>>8; + spi.size = data>>10; + spi.hold = data>>11; + spi.irq = data>>14; + spi.enable = data>>15; + + if(spi.enable == false) { + // Hrm, must be implicit as libnds does not release the hold + // before last transfer - or is spi.hold not delayed after all? + system.firmware.select(false); + system.powerMgr.select(false); + system.touchscreen.select(false); + } + } + if(mask & 0xffff0000) { + if(!spi.enable) return; + + SPIDevice* device = nullptr; + if(spi.device == SPI::flash) device = &system.firmware; + if(spi.device == SPI::power) device = &system.powerMgr; + if(spi.device == SPI::touch) device = &system.touchscreen; + + if(device) { + // SPI transfers are bidirectional so there's always a read+write. + device->select(true); + spi.data = device->transfer(data>>16); + device->select(spi.hold); + } + } +} + + + +uint32 ARM7TDMI::regRtc() { + // I've blithely assumed: pin = (out | ~dir) & in + // + // Something like that is necessary because Nintendo read-modify-writes + // the output pins. + return uint4( (rtc.out[0] | ~rtc.dir[0]) & rtc.in[0] )<<0 | rtc.dir[0]<<4 + | uint4( (rtc.out[1] | ~rtc.dir[1]) & rtc.in[1] )<<8 | rtc.dir[1]<<12; +} + +void ARM7TDMI::regRtc(uint32 data, uint32 mask) { + // It would've been nice if the clock was on the SPI bus, like the touchpad, + // firmware and power chips.. it seems that wasn't possible because of the + // bi-directional data pin. Software has to bit-bang the GPIO pins instead. + + if(mask & 0x00ff) { + rtc.out[0] = data>>0; // if dir==1, use output from the DS side. + rtc.dir[0] = data>>4; // if dir==0, use as input with pullup (?) + } + if(mask & 0xff00) { + rtc.out[1] = data>>0; // these may exist, but don't appear to be used. + rtc.dir[1] = data>>4; + } + // All pins can be either inputs or outputs. + // "in" is the value being driven externally (or 1, if not). + uint4 pins = (rtc.out[0] | ~rtc.dir[0]) & rtc.in[0]; + rtc.in[0] = system.clock.io(pins); +} + + + +uint32 ARM7TDMI::regSio() { + return sio.in<<0 | sio.dir<<4 | sio.irq<<8 | sio.mode<<14; +} + +void ARM7TDMI::regSio(uint32 data, uint32 mask) { + sio.out = data>>0; + sio.dir = data>>4; + sio.irq = data>>8; + sio.mode = data>>14; +} + diff --git a/bsnes/nds/cpu/arm946es.cpp b/bsnes/nds/cpu/arm946es.cpp new file mode 100644 index 00000000..e3b24577 --- /dev/null +++ b/bsnes/nds/cpu/arm946es.cpp @@ -0,0 +1,697 @@ + +ARM946ES::ARM946ES() { + itcm.data = new uint32_t[(itcm.size = 0x8000)/4]; + dtcm.data = new uint32_t[(dtcm.size = 0x4000)/4]; + bios.data = new uint32[(bios.size = 0x001000)/4](); + memset(bios.data, 0, bios.size); +} + +void ARM946ES::Thread() { arm9.main(); } + +void ARM946ES::power() { + // 2 * 33513982 MHz + if(thread) co_delete(thread); + thread = co_create(262144 * sizeof(void*), ARM946ES::Thread); + + vectorBase = 0xffff0000; + bxWithLoadedPC = true; + insnLatch = 0; + + memset(itcm.data, 0, itcm.size); + memset(dtcm.data, 0, dtcm.size); + + divMode = 0; rootMode = 0; + divByZero = 0; rootBusy = 0; + divBusy = 0; square = 0; + numerator = 0; squareRoot = 0; + denominator = 0; + quotient = 0; + remainder = 0; + + booted = 0; + flag300 = 0; + + slot1access = 1; + slot2access = 1; + ramPriority = 1; + + CPUCore::power(); + trace = false; + + control.mmu = false; + control.dcache = false; + control.icache = false; + + control.dtcm = false; + control.itcm = false; + control.dtcmLoad = false; + control.itcmLoad = false; + + control.endian = CR::little; + control.cachePolicy = CR::random; +} + +void ARM946ES::istep(unsigned clocks) { + arm7.clock -= clocks; + event.queue.step(clocks); +} + +void ARM946ES::step(unsigned clocks) { + return istep(clocks); +} + + + +void ARM946ES::main() { + itcmRegion = 0x00000000 | 14<<1; control.itcm = true; + dtcmRegion = 0x00800000 | 14<<1; control.dtcm = true; + updateTcm(); + + for(;;) { + if(arm7.clock < -256) + co_switch(arm7.thread); + + event.irq = interrupt.gate && (interrupt.enable & interrupt.flags); + //if(event.irq && !If) { + // print("arm9: irq (if=",hex<8>(interrupt.flags),")\n"); + //} + + if(Tf) execTHUMB(); + else execARM(); + } +} + + + +void ARM946ES::execARM() { + if(branched) { + //if(r[15] == 0) print(hex<8>(r[14]), ": jump to nullptr!\n"); + branched = false; r[15] &= ~3; + iexecute = fetch(r[15], Word, 0); r[15] += 4; + idecode = fetch(r[15], Word, 0); r[15] += 4; + } else { + iexecute = idecode, idecode = ifetch; + } + ifetch = fetch(r[15], Word, 1); + uint32 i = iexecute; + if(event.irq && !If) return irq(); + //if(trace) traceInsn(); + + if(i < 0xe0000000 && !evalCond(i>>28)) { r[15] += 4; return; } + + // opcode, sh, Rd, Rn, Rm, Rs + if(imatch("1111......../////")) { + if(imatch("111101x1u101/////")) { r[15] += 4; return; } // pld - reportedly NOP on DS? + if(imatch("1111101l..../////")) return armBranch (1, 1, i<<2 | (i>>23 & 2)); + return undefined(); + } + if(imatch("00x10xx0/////")) { + if(imatch("00110r10/// ..../")) return armWritePsr(i>>22, i>>16, armImmed(i, i>>8)); + if(imatch("00010r10/// 0000/")) return armWritePsr(i>>22, i>>16, armRm(i)); + if(imatch("00010r00/// 0000/")) return armReadPsr (i>>22, i>>12); + if(imatch("00010010/// 00l1/")) return armBranchEx( i>>5, i); + if(imatch("00010010/// 0111/")) return pfabort (); // bkpt + if(imatch("00010110/// 0001/")) return armClz ( i>>12, i); + if(imatch("00010ds0/// 0101/")) return armDspAdd (i>>21, i>>12, i>>16, i); + if(imatch("00010oo0/// 1yx0/")) return armDspMul (i>>21, i>>5, i>>16, i>>12, i, i>>8); + if(imatch("00010b00/// 1001/")) return armMemSwap (i>>22, i>>12, i>>16, i); + } + if(imatch("000...../// 1..1/")) { + if(imatch("0000luas/// 1001/")) return armMultiply(i>>20, i>>16, i>>12, i, i>>8); + if(imatch("000pu0w0/// 11s1/")) return armMem_v5 (i>>20, i>>5, i>>12, i>>16, armRm(i)); + if(imatch("000pu0wl/// 1sh1/")) return armMem_v4 (i>>20, i>>5, i>>12, i>>16, armRm(i)); + if(imatch("000pu1w0/// 11s1/")) return armMem_v5 (i>>20, i>>5, i>>12, i>>16, armOffset8(i, i>>8)); + if(imatch("000pu1wl/// 1sh1/")) return armMem_v4 (i>>20, i>>5, i>>12, i>>16, armOffset8(i, i>>8)); + } + if(imatch("001aaaas/// ..../")) return armData (i>>20, i>>12, i>>16, armImmed(i, i>>8)); + if(imatch("000aaaas/// .sh0/")) return armData (i>>20, i>>12, i>>16, shiftImm(i, i>>5, i>>7)); + if(imatch("010pubwl/// ..../")) return armMem (i>>20, i>>12, i>>16, armOffset12(i)); + if(imatch("011pubwl/// ...0/")) return armMem (i>>20, i>>12, i>>16, shiftImm(i, i>>5, i>>7)); + if(imatch("100puswl/// ..../")) return armBlock (i>>20, i>>16, i); + if(imatch("101l..../// ..../")) return armBranch (i>>24, 0, i<<2); + if(imatch("000aaaas/// 0sh1/")) return armDataRs (i>>20, i>>12, i>>16, i, i>>5, i>>8); + + if(imatch("1110..../// ..../")) return dataCop (i>>8, i>>20, i>>12, i>>16, i, i>>4); + if(imatch("1111..../// ..../")) return swi(); + return undefined(); +} + +void ARM946ES::execTHUMB() { + if(branched) { + //if(r[15] == 0) print(hex<8>(r[14]), ": jump to nullptr!\n"); + branched = false; r[15] &= ~1; + iexecute = fetch(r[15], Half, 0) >> 8*(r[15] & 2) & 0xffff; r[15] += 2; + idecode = fetch(r[15], Half, 1) >> 8*(r[15] & 2) & 0xffff; r[15] += 2; + } else { + iexecute = idecode, idecode = ifetch; + } + ifetch = fetch(r[15], Half, 1) >> 8*(r[15] & 2) & 0xffff; + uint16 i = iexecute; + + if(event.irq && !If) return irq(); + //if(trace) traceInsn(); + + if(imatch("00011ismmmnnnddd")) return thumbAddSub (i>>9, i, i>>3, i>>6); + if(imatch("000ssiiiiimmmddd")) return thumbShiftImm(i>>11, i, i>>3, i>>6); + if(imatch("001oodddiiiiiiii")) return thumbDataImm (i>>11, i>>8, i); + if(imatch("010000oooommmddd")) return thumbDataLo (i>>6, i, i>>3); + if(imatch("010001oodmmmmddd")) return thumbDataHi (i>>8, (i&7)+(i>>4&8), i>>3); + + if(imatch("0101ooommmnnnddd")) return thumbMemReg (i>>9, i, i>>3, i>>6); + if(imatch("011bliiiiinnnddd")) return thumbMemImm (i>>11, i, i>>3, i>>6); + if(imatch("1000liiiiinnnddd")) return thumbMemImm (i>>11, i, i>>3, i>>6); + + if(imatch("10111110........")) return pfabort(); // bkpt + if(imatch("10110000siiiiiii")) return thumbAddSP ( i>>7, i); + if(imatch("01001dddrrrrrrrr")) return thumbRelative(i>>11, i>>8, i); + if(imatch("1001odddrrrrrrrr")) return thumbRelative(i>>11, i>>8, i); + if(imatch("1010odddrrrrrrrr")) return thumbRelative(i>>11, i>>8, i); + + if(imatch("1101ccccrrrrrrrr")) return thumbCond ( i>>8, i); + if(imatch("11100rrrrrrrrrrr")) return thumbBranch (i); + if(imatch("11110rrrrrrrrrrr")) return thumbBh (i); + if(imatch("111t1rrrrrrrrrrr")) return thumbBlx (i>>12, i); + + if(imatch("1o..lnnnrrrrrrrr")) return thumbBlock (i>>11, i>>8, i); + + return undefined(); +} + + + +uint32 ARM946ES::fetch(uint32 addr, uint32 size, bool s) { + istep(1); // Assume cached for now + + if(itcmRCompare == (itcmRMask & addr)) { return itcm.read(addr % 0x8000, size); } + /* DTCM is not executable */ + + switch(addr >> 24) { + case 0x2: return system.ewram.read(addr % 0x400000, size); + case 0x3: return system.swram[addr>>14 & 1].read(addr % 0x4000, size); + case 0x6: return system.vmap.arm9[addr>>21 & 7][addr>>14 & 63].read(addr, size); + } + if(addr >= 0xffff0000) return bios.read(addr & bios.size-1, size); + return 0; +} + +uint32 ARM946ES::read(uint32 addr, uint32 size, bool s) { + if(itcmRCompare == (itcmRMask & addr)) { istep(1); return itcm.read(addr % 0x8000, size); } + if(dtcmRCompare == (dtcmRMask & addr)) { return dtcm.read(addr % 0x4000, size); } + + const int w = 6*!s + 2; // 32-bit bus timing + const int h = 6*!s + (size==Word? 4 : 2); // 16-bit bus timing + //const int e = 2*!s + h; // EWRAM timing + + //if((addr & 0xf3ff000) == 0x23ff000) { + // istep(e); + // uint32 data = system.ewram.read(addr % 0x400000, size); + // print(hex<8>(arm9.event.queue.time), " ",hex<8>(r[15])," arm9: r ",hex<8>(addr),":",size," = ",hex<8>(data),"\n"); + // return data; + //} + + switch(addr >> 24) { + case 0x2: istep(3); return system.ewram.read(addr % 0x400000, size); + case 0x3: istep(w); return system.swram[addr>>14 & 1].read(addr % 0x4000, size); + case 0x4: istep(w); { //return readReg(addr, size); { + uint32 data = readReg(addr, size); + //if(addr != 0x40001a0 && addr != 0x40001a4 && addr != 0x4100010) + // print(hex<8>(arm9.event.queue.time), " ",hex<8>(r[15])," arm9: r ",hex<8>(addr),":",size," = ",hex<8>(data),"\n"); + return data; + } + case 0x5: istep(h); return ppu[addr>>10 & 1].readPalette(addr % 0x400); + case 0x6: istep(h); return system.vmap.arm9[addr>>21 & 7][addr>>14 & 63].read(addr, size); + case 0x7: istep(w); return ppu[addr>>10 & 1].readOam(addr % 0x400); + } + istep(w); if(addr >= 0xffff0000) return bios.read(addr & bios.size-1, size); + return 0; +} + +void ARM946ES::write(uint32 addr, uint32 size, bool s, uint32 data) { + if(itcmWCompare == (itcmWMask & addr)) { istep(1); return itcm.write(addr % 0x8000, size, data); } + if(dtcmWCompare == (dtcmWMask & addr)) { return dtcm.write(addr % 0x4000, size, data); } + + //if((addr & 0xf3ff000) == 0x23ff000) + // print(hex<8>(arm9.event.queue.time), " ",hex<8>(r[15]), " arm9: w ",hex<8>(addr),":",size," = ",hex<8>(data),"\n"); + + const int w = 6*!s + 2; // 32-bit bus timing + const int h = 6*!s + (size==Word? 4 : 2); // 16-bit bus timing + //const int e = 2*!s + h; // EWRAM timing + + switch(addr >> 24) { + case 0x2: istep(3); return system.ewram.write(addr % 0x400000, size, data); + case 0x3: istep(w); return system.swram[addr>>16 & 1].write(addr % 0x4000, size, data); + case 0x4: istep(w); { //return writeReg(addr, size, data); + //if(addr != 0x04000400) + // print(hex<8>(arm9.event.queue.time), " ", hex<8>(r[15])," arm9: w ",hex<8>(addr),":",size," = ",hex<8>(data),"\n"); + writeReg(addr, size, data); + return; + } + case 0x5: istep(h); return ppu[addr>>10 & 1].writePalette(addr % 0x400, size, data); + case 0x6: istep(h); return system.vmap.arm9[addr>>21 & 7][addr>>14 & 63].write(addr, size, data); + case 0x7: istep(w); return ppu[addr>>10 & 1].writeOam(addr % 0x400, size, data); + } + istep(w); +} + +void ARM946ES::dataCop(uint4 cpno, uint4 op1, uint4 ird, uint4 irn, uint4 irm, uint4 op2) { + if(cpno == 15) { + auto &rd = r[ird]; + uint32 rm = r[irm]; + r[15] += 4; + + if(op2 & 1) { // MRC, MCR + switch(op1<<12 | irn<<8 | irm<<4 | op2>>1) { + + case 0x1000: // c0,c0,0 Processor ID + rd = 'A'<<24; // Implementor ARM + rd |= 0<<20; // Variant 0 + rd |= 5<<16; // Architecture v5 + rd |= 0x946<< 4; // Model 946 + rd |= 1<< 0; // Revision 1 + return; + + case 0x1001: // c0,c0,1 Cache information + rd = 0x0f<<24; // type B Harvard + rd |= 0x0d2<<12; // 4K data, 4-way, 32-byte lines + rd |= 0x112<< 0; // 8K insn, 4-way, 32-byte lines + return; + + case 0x1002: // c0,c0,2 TCM information + rd = 5<<18; // 16K dtcm + rd |= 6<< 6; // 32K itcm + return; + + case 0x1100: // c1,c0,0 Control register + rd = control.mmu<<0 | control.dcache<<2 | 1<<3 /*write buffer*/ + | 1<<4 | 1<<5 | 1<<6 /*32 bit only, late abort model*/ + | control.endian<<7 | control.icache<<12 | !!vectorBase<<13 + | control.cachePolicy<<14 | !bxWithLoadedPC<<15 + | control.dtcm<<16 | control.dtcmLoad<<17 + | control.itcm<<18 | control.itcmLoad<<19; + return; + + case 0x0100: + control.mmu = rd >> 0; + control.dcache = rd >> 1; + control.endian = rd >> 7; + control.icache = rd >> 12; + vectorBase = rd & 1<<13? 0xffff0000 : 0; + control.cachePolicy = rd >> 14; + bxWithLoadedPC = rd & 1<<15? false : true; + control.dtcm = rd >> 16; + control.dtcmLoad = rd >> 17; + control.itcm = rd >> 18; + control.itcmLoad = rd >> 19; + + updateTcm(); + return; + + case 0x0900: case 0x1900: // c9,c0,0 Lock dcache + case 0x0901: case 0x1901: // c9,c0,1 Lock icache + return; + + case 0x0910: // c9,c1,0 DTCM mapping + dtcmRegion = rd; + updateTcm(); + return; + case 0x1910: + rd = dtcmRegion; + return; + + case 0x0911: // c9,c1,1 ITCM mapping + itcmRegion = rd; + updateTcm(); + return; + case 0x1911: + rd = itcmRegion; + return; + + case 0x0200: case 0x1200: // c2,c0,0 Region data cache bits + case 0x0201: case 0x1201: // c2,c0,1 Region insn cache bits + case 0x0300: case 0x1300: // c3,c0,0 Region data buffer bits + case 0x0500: case 0x1500: // c5,c0,0 Region data permissions + case 0x0501: case 0x1501: // c5,c0,1 Region insn permissions + case 0x0502: case 0x1502: // c5,c0,2 Region data permissions - extended + case 0x0503: case 0x1503: // c5,c0,3 Region insn permissions - extended + return; + + case 0x0600: case 0x1600: case 0x0601: case 0x1601: // c6,cN,0 Region mappings + case 0x0610: case 0x1610: case 0x0611: case 0x1611: + case 0x0620: case 0x1620: case 0x0621: case 0x1621: + case 0x0630: case 0x1630: case 0x0631: case 0x1631: + case 0x0640: case 0x1640: case 0x0641: case 0x1641: + case 0x0650: case 0x1650: case 0x0651: case 0x1651: + case 0x0660: case 0x1660: case 0x0661: case 0x1661: + case 0x0670: case 0x1670: case 0x0671: case 0x1671: + return; + + case 0x0704: // c7,c0,4 Wait for Interrupt + case 0x0782: // c7,c8,2 (alternate version) + //print("arm9: wait (ime=",interrupt.gate,", ie=",hex<8>(interrupt.enable),")\n"); + powerState = waiting; + for(;;) { + // Because this one is integrated with the ARM9, + // it's "behind" the IRQ line and knows nothing about IME/IE/IF. + if(interrupt.gate && (interrupt.enable & interrupt.flags)) { + powerState = running; + break; + } + istep(256); + if(arm7.clock < -256) + co_switch(arm7.thread); + } + return; + + case 0x0750: // c7, c5,0 Invalidate icache entirely + case 0x0751: // c7, c5,1 Invalidate icache by address + case 0x0752: // c7, c5,2 Invalidate icache by line (?) + case 0x07d1: // c7,c13,1 Preload icache by address + return; + + case 0x0760: // c7, c6,0 Invalidate dcache entirely + case 0x0761: // c7, c6,1 Invalidate dcache by address + case 0x0762: // c7, c6,2 Invalidate dcache by line (? zelda gallery uses this) + + //case 0x07a0://c7,c10,0 Clean dcache entirely (?) + case 0x07a1: // c7,c10,1 Clean dcache by address + case 0x07a2: // c7,c10,2 Clean dcache by line + case 0x07a4: // c7,c10,4 Drain write buffer + + //case 0x07e0://c7,c14,0 Flush dcache entirely (?) + case 0x07e1: // c7,c14,1 Flush dcache by address + case 0x07e2: // c7,c14,2 Flush dcache by line + return; + + case 0x0f00: case 0x1f00: // 0,c15,c0,0 Cache control + case 0x6f00: case 0x7f00: // 3,c15,c0,0 Cache tag/data index + case 0x6f01: case 0x7f01: // 3,c15,c0,1 R/W icache tag + case 0x6f02: case 0x7f02: // 3,c15,c0,2 R/W dcache tag + case 0x6f03: case 0x7f03: // 3,c15,c0,3 R/W icache data + case 0x6f04: case 0x7f04: // 3,c15,c0,4 R/W dcache data + return; + + } + } + } + bool iscdp = op2&1, isld = op1&1; + print("arm9: ",hex<8>(r[15])," undefined ", iscdp? "cdp" : isld? "mrc" : "mcr", " p",cpno,", ", + iscdp? (unsigned)op1 : op1>>1, ", ", iscdp? "cr":"r", ird, ", cr", irn, ", cr", irm, ", ", op2>>1, "\n"); + return undefined(); +} + + + +uint32 ARM946ES::readReg(uint32 addr, uint32 size) { + switch(addr-0x4000000 & ~3) { + + // These registers shouldn't be here - but they contain bits from logically + // separate hardware units, so it's not clear where else to put them. + + case 0x0000: // Display 0 / PPU0 BG, OBJ control + return (video.frameBuffer<<18 & 0xc0000) + | video.source[0]<<16 | ppu[0].regControl(); + + case 0x1000: // Display 1 / PPU1 BG, OBJ control + return video.source[1]<<16 | ppu[1].regControl(); + + case 0x0008: case 0x1008: // BG0,BG1 + case 0x000c: case 0x100c: // BG2,BG3 + return ppu[addr>>12 & 1].regBg((addr>>1 & 2) + 0)<<0 + | ppu[addr>>12 & 1].regBg((addr>>1 & 2) + 1)<<16; + + case 0x0010: case 0x1010: // BG0H,V + case 0x0014: case 0x1014: // BG1H,V + case 0x0018: case 0x1018: // BG2H,V + case 0x001c: case 0x101c: // BG3H,V + return ppu[addr>>12 & 1].regBgOffs(addr>>2 & 3); + + case 0x0048: case 0x1048: // Window area 0,1,out,obj + return ppu[addr>>12 & 1].regWinArea(); + + case 0x0050: case 0x1050: // Blend control + return ppu[addr>>12 & 1].regBlend(); + + // Miscellaneous graphics registers + case 0x0060: return gpu.regRenderOptions(); + case 0x0064: return video.regCapture(); + case 0x006c: return video.regBrightness(0); + + case 0x1060: return 0; + case 0x1064: return 0; + case 0x1068: return 0; + case 0x106c: return video.regBrightness(1); + + // Memory control + case 0x0204: return ramPriority<<15 | slot1access<<11 + | slot2access<<7 | regSlot2Control(); + + case 0x0240: return system.regVmap(0); + case 0x0244: return system.regVmap(1); + case 0x0248: return system.regVmap(2); + + // Math + case 0x0280: return regDivideControl(); + case 0x0290: return regNumerator(0); + case 0x0294: return regNumerator(1); + case 0x0298: return regDenominator(0); + case 0x029c: return regDenominator(1); + case 0x02a0: return regQuotient(0); + case 0x02a4: return regQuotient(1); + case 0x02a8: return regRemainder(0); + case 0x02ac: return regRemainder(1); + + case 0x02b0: return regSquareRootControl(); + case 0x02b4: return regSquareRoot(); + case 0x02b8: return regSquare(0); + case 0x02bc: return regSquare(1); + + case 0x0300: return booted<<0 | flag300<<1; + + // Power + case 0x0304: + return video.screensPowered<< 0 | ppu[0].powered<<1 + | video.ppu0Screen <<15 | ppu[1].powered<<9; + + // Render status + case 0x0320: return gpu.regRenderLoad(); + + // This shouldn't exist, but various games read it nonetheless.. + case 0x04a4: return 0; + + // Geometry status + case 0x0600: return gpu.regGeomStatus(); + case 0x0604: return gpu.regGeomLoad(); + + case 0x0620: case 0x0624: case 0x0628: case 0x062c: + return gpu.regGeomPosition((addr - 0x4000620)/4); + + case 0x0630: case 0x0634: + return gpu.regGeomNormal((addr - 0x4000630)/4); + + case 0x0640: case 0x0644: case 0x0648: case 0x064c: + case 0x0650: case 0x0654: case 0x0658: case 0x065c: + case 0x0660: case 0x0664: case 0x0668: case 0x066c: + case 0x0670: case 0x0674: case 0x0678: case 0x067c: + return gpu.regClipMatrix((addr - 0x4000640)/4); + + case 0x0680: case 0x0684: case 0x0688: + case 0x068c: case 0x0690: case 0x0694: + case 0x0698: case 0x069c: case 0x06a0: + return gpu.regLightMatrix((addr - 0x4000680)/4); + + } + return CPUCore::readReg(addr, size); +} + +void ARM946ES::writeReg(uint32 addr, uint32 size, uint32 data) { + uint32 mask = 0xffffffff; + if(size == Half) mask = 0xffff << 8*(addr & 2); + if(size == Byte) mask = 0xff << 8*(addr & 3); + + data &= mask; + + switch(addr-0x4000000 & ~3) { + + case 0x0000: // Display 0 / PPU0 control + if(mask & 0x000f0000) { + // These bits go to the display controller - not PPU0. + video.frameBuffer &= ~0xc; + video.frameBuffer |= 0xc & data>>16; + video.source[0] = 0x3 & data>>16; + } + ppu[0].regControl(data, mask); + return; + + case 0x1000: // Display 1 / PPU1 control + if(mask & 0x000f0000) { + // Framebuffer/FIFO sources aren't supported here. + video.source[1] = 0x1 & data>>16; + } + ppu[1].regControl(data, mask); + return; + + case 0x0008: case 0x1008: // BGn control + case 0x000c: case 0x100c: // + if(mask & 0x0000ffff) ppu[addr>>12 & 1].regBg((addr>>1 & 2) + 0, data>>0, mask>>0); + if(mask & 0xffff0000) ppu[addr>>12 & 1].regBg((addr>>1 & 2) + 1, data>>16, mask>>16); + return; + + case 0x0010: case 0x1010: // BGn H,V scroll + case 0x0014: case 0x1014: // + case 0x0018: case 0x1018: // + case 0x001c: case 0x101c: return ppu[addr>>12 & 1].regBgOffs(addr>>2 & 3, data, mask); + + case 0x0020: case 0x1020: // BG2 affine A, B, C, D + case 0x0024: case 0x1024: // + case 0x0028: case 0x1028: // BG2 origin X, Y + case 0x002c: case 0x102c: return ppu[addr>>12 & 1].regBgAffine(2, addr>>2 & 3, data, mask); + + case 0x0030: case 0x1030: // BG3 affine A, B, C, D + case 0x0034: case 0x1034: // + case 0x0038: case 0x1038: // BG3 origin X, Y + case 0x003c: case 0x103c: return ppu[addr>>12 & 1].regBgAffine(3, addr>>2 & 3, data, mask); + + case 0x0040: case 0x1040: return ppu[addr>>12 & 1].regWinDims(0, data, mask); // Window 0,1 X range + case 0x0044: case 0x1044: return ppu[addr>>12 & 1].regWinDims(1, data, mask); // 0,1 Y range + case 0x0048: case 0x1048: return ppu[addr>>12 & 1].regWinArea(data, mask); // area 0,1,out,obj + case 0x004c: case 0x104c: return; // Mosaic BG,OBJ X,Y + + case 0x0050: case 0x1050: // Blend control + case 0x0054: case 0x1054: return ppu[addr>>12 & 1].regBlend(addr>>2 & 1, data, mask); + + case 0x0058: case 0x1058: return; // not present, but frequently zeroed anyway + case 0x005c: case 0x105c: return; // + + // Some miscellaneous registers, none of which belong here... hunh. + case 0x0060: return gpu.regRenderOptions(data, mask); + case 0x0064: return video.regCapture(data, mask); + case 0x0068: return video.regFifo(data); + case 0x006c: return video.regBrightness(0, data, mask); + + case 0x1060: return; + case 0x1064: return; + case 0x1068: return; + case 0x106c: return video.regBrightness(1, data, mask); + + // Memory control + case 0x0204: + if(mask & 0x00ff) { + slot2access = !(data & 1<<7); + } + if(mask & 0xff00) { + slot1access = !(data & 1<<11); + ramPriority = !(data & 1<<15); + } + return regSlot2Control(data, mask); + + case 0x0240: return system.regVmap(0, data, mask); + case 0x0244: return system.regVmap(1, data, mask); + case 0x0248: return system.regVmap(2, data, mask); + + // Math + case 0x0280: return regDivideControl(data, mask); + case 0x0290: return regNumerator(0, data, mask); + case 0x0294: return regNumerator(1, data, mask); + case 0x0298: return regDenominator(0, data, mask); + case 0x029c: return regDenominator(1, data, mask); + + case 0x02b0: return regSquareRootControl(data, mask); + case 0x02b8: return regSquare(0, data, mask); + case 0x02bc: return regSquare(1, data, mask); + + case 0x0300: + if(mask & 0xff) { + booted |= data>>0; + flag300 = data>>1; + } + return; + + case 0x0304: // Power control + if(mask & 0x00ff) { + video.screensPowered = data>>0; + ppu[0].powered = data>>1; + //gpu.renderPowered = data>>2; + //gpu.geomPowered = data>>3; + } + if(mask & 0xff00) { + ppu[1].powered = data>>9; + video.ppu0Screen = data>>15; + } + return; + + // Toon edge table + case 0x0330: case 0x0334: case 0x0338: case 0x033c: + return gpu.regRenderEdgeTable((addr - 0x4000330)/4, data, mask); + + // Misc + case 0x0340: return gpu.regRenderMinAlpha(data, mask); + case 0x0350: return gpu.regRenderClearColor(data, mask); + case 0x0354: return gpu.regRenderClearCoord(data, mask); + case 0x0358: return gpu.regRenderFogColor(data, mask); + case 0x035c: return gpu.regRenderFogCoord(data, mask); + + // Fog table + case 0x0360: case 0x0364: case 0x0368: case 0x036c: + case 0x0370: case 0x0374: case 0x0378: case 0x037c: + return gpu.regRenderFogTable((addr - 0x4000360)/4, data, mask); + + // Toon shade table + case 0x0380: case 0x0384: case 0x0388: case 0x038c: + case 0x0390: case 0x0394: case 0x0398: case 0x039c: + case 0x03a0: case 0x03a4: case 0x03a8: case 0x03ac: + case 0x03b0: case 0x03b4: case 0x03b8: case 0x03bc: + return gpu.regRenderToonTable((addr - 0x4000380)/4, data, mask); + + // GPU command pipe - buffered - mirrored to support STM + case 0x0400: case 0x0404: case 0x0408: case 0x040c: case 0x0410: case 0x0414: case 0x0418: case 0x041c: + case 0x0420: case 0x0424: case 0x0428: case 0x042c: case 0x0430: case 0x0434: case 0x0438: case 0x043c: + return gpu.sendGeomBuffered(data); + + // GPU command pipe - immediate - the address itself is used as command number. + case 0x0440: case 0x0444: case 0x0448: case 0x044c: case 0x0450: case 0x0454: case 0x0458: case 0x045c: + case 0x0460: case 0x0464: case 0x0468: case 0x046c: case 0x0470: case 0x0474: case 0x0478: case 0x047c: + case 0x0480: case 0x0484: case 0x0488: case 0x048c: case 0x0490: case 0x0494: case 0x0498: case 0x049c: + case 0x04a0: case 0x04a4: case 0x04a8: case 0x04ac: case 0x04b0: case 0x04b4: case 0x04b8: case 0x04bc: + case 0x04c0: case 0x04c4: case 0x04c8: case 0x04cc: case 0x04d0: case 0x04d4: case 0x04d8: case 0x04dc: + case 0x04e0: case 0x04e4: case 0x04e8: case 0x04ec: case 0x04f0: case 0x04f4: case 0x04f8: case 0x04fc: + case 0x0500: case 0x0504: case 0x0508: case 0x050c: case 0x0510: case 0x0514: case 0x0518: case 0x051c: + case 0x0520: case 0x0524: case 0x0528: case 0x052c: case 0x0530: case 0x0534: case 0x0538: case 0x053c: + case 0x0540: case 0x0544: case 0x0548: case 0x054c: case 0x0550: case 0x0554: case 0x0558: case 0x055c: + case 0x0560: case 0x0564: case 0x0568: case 0x056c: case 0x0570: case 0x0574: case 0x0578: case 0x057c: + case 0x0580: case 0x0584: case 0x0588: case 0x058c: case 0x0590: case 0x0594: case 0x0598: case 0x059c: + case 0x05a0: case 0x05a4: case 0x05a8: case 0x05ac: case 0x05b0: case 0x05b4: case 0x05b8: case 0x05bc: + case 0x05c0: case 0x05c4: case 0x05c8: case 0x05cc: case 0x05d0: case 0x05d4: case 0x05d8: case 0x05dc: + case 0x05e0: case 0x05e4: case 0x05e8: case 0x05ec: case 0x05f0: case 0x05f4: case 0x05f8: case 0x05fc: + return gpu.sendGeomImmediate(addr>>2 & 0x7f, data); + + // Geometry engine + case 0x0600: return gpu.regGeomStatus(data, mask); + case 0x0610: return gpu.regGeomMaxPointDepth(data, mask); + + // zelda gallery writes 0x2468ace0 here - ??? + case 0x0640: break; + } + return CPUCore::writeReg(addr, size, data); +} + + +void ARM946ES::updateTcm() { + uint32 itcmAddr = 0, itcmSize = itcmRegion>>1 & 0x1f; + uint32 dtcmAddr = dtcmRegion & ~0xfff, dtcmSize = dtcmRegion>>1 & 0x1f; + + // Disable by default + itcmRCompare = itcmWCompare = ~0; + dtcmRCompare = dtcmWCompare = ~0; + itcmRMask = itcmWMask = 0; + dtcmRMask = dtcmWMask = 0; + + // Enable bit enables access; load bit disables reading + if(control.itcm) itcmWCompare = itcmAddr, itcmWMask = -1 << 9+itcmSize; + if(control.dtcm) dtcmWCompare = dtcmAddr, dtcmWMask = -1 << 9+dtcmSize; + if(control.itcm && !control.itcmLoad) itcmRCompare = itcmAddr, itcmRMask = -1 << 9+itcmSize; + if(control.dtcm && !control.dtcmLoad) dtcmRCompare = dtcmAddr, dtcmRMask = -1 << 9+dtcmSize; +} + + + +#include "math.cpp" diff --git a/bsnes/nds/cpu/bit.hpp b/bsnes/nds/cpu/bit.hpp new file mode 100644 index 00000000..e03e03c4 --- /dev/null +++ b/bsnes/nds/cpu/bit.hpp @@ -0,0 +1,66 @@ + +namespace Bit { + + template + constexpr int count(T n) { + return n == 0 || w == 0? n + : count(n>>w & (1<(n & (1< constexpr long lowest_bit_no(long x) { + return !x? -1 : !s? 0 : + x & (1<(x) + : s + lowest_bit_no(x >> s); +} + +constexpr long binary(const char *s) { + return !*s? 0 : (*s=='1') << bitpos(s) | binary(s+1); +} +constexpr long mask(const char *s) { + return !*s? 0 : (*s=='0'||*s=='1') << bitpos(s) | mask(s+1); +} +constexpr long field(const char *s) { + return !*s? 0 : (*s!=' '&& isfield(*s)) << bitpos(s) | field(s+1); +} +constexpr bool match(long data, const char *s) { + return (data & mask(s)) == binary(s); +} + +// Masks all 'bits' from the input and shifts them down into one contiguous +// value. This inlines to a sequence of &, >> and + instructions. +// Example: +// collect(i) +// joins i's 1st, 3rd, and 5th nibbles (0x12345 => 0x135). +template constexpr long collect(long data); +template constexpr long collect_field(long data) { + return (data & (1<> nmask)>(data >> nmask) << nmask*(bits&1)); +} + +template constexpr long collect(long data) { + return collect_field(data); +} +template<> constexpr long collect<0>(long data) { + return 0; +} + +}; diff --git a/bsnes/nds/cpu/core.cpp b/bsnes/nds/cpu/core.cpp new file mode 100644 index 00000000..1bfcf4f3 --- /dev/null +++ b/bsnes/nds/cpu/core.cpp @@ -0,0 +1,214 @@ + +void ARMCore::power() { + for(int n = 0; n < 16; n++) r[n] = 0; + for(int n = 0; n < 7; n++) r_fiq[n] = 0; + for(int n = 0; n < 2; n++) r_irq[n] = r_svc[n] = r_abt[n] = r_und[n] = 0; + + spsr_none = spsr_fiq = spsr_irq = spsr_svc = spsr_abt = spsr_und = 0; + carryout = 0; + Nf = Cf = Vf = Qf = 0; + Zf = -1; + + reset(); +} + + + +uint32& ARMCore::spsr() { + return mode == FIQ? spsr_fiq : mode == IRQ? spsr_irq + : mode == SVC? spsr_svc : mode == UND? spsr_und + : mode == ABT? spsr_abt : spsr_none; +} + +uint32 ARMCore::readCpsr() { + uint32 n = Nf & 1<<31, c = Cf & 1<<31; + uint32 v = Vf & 1<<31, q = Qf & 1<<31; + uint32 z = !Zf <<31; + + return n>>0 | z>>1 | c>>2 | v>>3 | q>>4 | If<<7 | Ff<<6 | Tf<<5 | mode<<0; +} + +void ARMCore::writeCpsr(uint32 value, unsigned mask) { + if(mask & 8) { + Nf = value<<0 & 1<<31; Zf = !(value<<1 & 1<<31); + Cf = value<<2 & 1<<31; Vf = value<<3 & 1<<31; + Qf = value<<4 & 1<<31; + } + if(mode == USR) + return; // cpsr_c is privileged + + if(mask & 1) { + swapBank(mode); + If = value>>7 & 1; Ff = value>>6 & 1; + Tf = value>>5 & 1; mode = value & 0x1f; + + mode |= 0x10; // enforce 32-bit addressing + if(mode & 0x0c) + mode |= 0x03; // enforce valid mode bits + swapBank(mode); + } +} + +void ARMCore::vector(uint32 offset, unsigned tomode) { + uint32 psr = readCpsr(); + + swapBank(mode); + swapBank(mode = tomode); + + // vector() is called between the instruction fetch and PC increment.. + // therefore in ARM mode, r15 == PC+8. THUMB requires an adjustment + // (done in the caller). + r[14] = r[15] - 4; + r[15] = vectorBase + offset; + If = 1; + Tf = 0; + spsr() = psr; + branched = true; +} + +void ARMCore::swapBank(unsigned mode) { + uint32 *bank = nullptr, *user = &r[15]; + unsigned count = 0; + + if(mode == FIQ) bank = &r_fiq[count = 7]; + if(mode == IRQ) bank = &r_irq[count = 2]; + if(mode == SVC) bank = &r_svc[count = 2]; + if(mode == ABT) bank = &r_abt[count = 2]; + if(mode == UND) bank = &r_und[count = 2]; + + while(count--) std::swap(*--bank, *--user); +} + + + +bool ARMCore::evalCond(unsigned cond) { + if(cond == 14) return true; + if(cond == 0) return (Zf == 0); // eq + if(cond == 1) return !(Zf == 0); // ne + if(cond == 2) return (Cf < 0); // hs / cs + if(cond == 3) return !(Cf < 0); // lo / cc + if(cond == 8) return (Cf < 0 && Zf); // hi + if(cond == 9) return !(Cf < 0 && Zf); // ls + if(cond == 10) return ((Nf^Vf) >= 0); // ge + if(cond == 11) return !((Nf^Vf) >= 0); // lt + if(cond == 12) return ((Nf^Vf) >= 0 && Zf); // gt + if(cond == 13) return !((Nf^Vf) >= 0 && Zf); // le + if(cond == 4) return (Nf < 0); // mi + if(cond == 5) return !(Nf < 0); // pl + if(cond == 6) return (Vf < 0); // vs + if(cond == 7) return !(Vf < 0); // vc + return false; +} + +void ARMCore::branch(bool tf, uint32 target) { + r[15] = target; + Tf = tf; + branched = true; +} + + + +uint32 ARMCore::load(uint32 addr, uint32 size) { + uint32 data = read(addr, size, false); + data = ror(data, 8*(addr & 3)); + step(1); + + if(size == Half) data &= 0xffff; + if(size == Byte) data &= 0xff; + return data; +} + +void ARMCore::store(uint32 addr, uint32 size, uint32 data) { + if(size == Half) data &= 0xffff, data *= 0x00010001; + if(size == Byte) data &= 0xff, data *= 0x01010101; + + write(addr, size, false, data); +} + + + +ARMCore::SOut ARMCore::lsl(uint32 rm, uint8 rs) { + if(rs == 0) return {rm, Cf}; + else return {rs>31? 0 : rm << rs, + rs>32? 0 : rm << rs-1}; +} +ARMCore::SOut ARMCore::lsr(uint32 rm, uint8 rs) { + if(rs == 0) return {rm, Cf}; + else return {rs>31? 0 : rm >> rs, + rs>32? 0 : rm << 32-rs}; +} +ARMCore::SOut ARMCore::asr(uint32 rm, uint8 rs) { + if(rs == 0) return {rm, Cf}; + else return {rs>31? (int32)rm>>31 : (int32)rm >> rs, + rs>32? rm : rm << 32-rs}; +} +ARMCore::SOut ARMCore::ror(uint32 rm, uint8 rs) { + if(rs == 0) return {rm, Cf}; + if(!(rs &= 31)) return {rm, rm}; // rs == multiple of 32 + else return {rm << 32-rs | rm >> rs, rm << 32-rs}; +} +ARMCore::SOut ARMCore::rrx(uint32 rm) { + return {(Cf & 1<<31) | rm >> 1, rm << 31}; +} + +ARMCore::SOut ARMCore::shiftImm(uint4 irm, uint2 opcode, uint5 rs) { + if(opcode == 0) return lsl(r[irm], rs); + if(opcode == 1) return lsr(r[irm], rs? (uint8)rs : 32); + if(opcode == 2) return asr(r[irm], rs? (uint8)rs : 32); + if(rs != 0) return ror(r[irm], rs); + if(rs == 0) return rrx(r[irm]); +} + +void ARMCore::alu(unsigned opcode, uint32& rd, uint32 rn, SOut rm) { + if(opcode == 13*2+0) return bitf(0, rd = rm, rm); // mov + if(opcode == 2*2+0) return sumf(0, rd = rn - rm, rn,~rm); // sub + if(opcode == 4*2+0) return sumf(0, rd = rn + rm, rn, rm); // add + if(opcode == 0*2+0) return bitf(0, rd = rn & rm, rm); // and + if(opcode == 12*2+0) return bitf(0, rd = rn | rm, rm); // orr + if(opcode == 14*2+0) return bitf(0, rd = rn &~rm, rm); // bic + if(opcode == 1*2+0) return bitf(0, rd = rn ^ rm, rm); // eor + + if(opcode == 13*2+1) return bitf(1, rd = rm, rm); // movs + if(opcode == 10*2+1) return sumf(1, rn - rm, rn,~rm); // cmps + if(opcode == 11*2+1) return sumf(1, rn + rm, rn, rm); // adds + + if(opcode == 2*2+1) return sumf(1, rd = rn - rm, rn,~rm); // subs + if(opcode == 4*2+1) return sumf(1, rd = rn + rm, rn, rm); // adds + if(opcode == 0*2+1) return bitf(1, rd = rn & rm, rm); // ands + if(opcode == 12*2+1) return bitf(1, rd = rn | rm, rm); // orrs + if(opcode == 14*2+1) return bitf(1, rd = rn &~rm, rm); // bics + if(opcode == 1*2+1) return bitf(1, rd = rn ^ rm, rm); // eors + if(opcode == 8*2+1) return bitf(1, rn & rm, rm); // tsts + if(opcode == 9*2+1) return bitf(1, rn ^ rm, rm); // teqs + + if(opcode == 3*2+0) return sumf(0, rd = rm - rn, ~rn, rm); // rsb + if(opcode == 5*2+0) return sumf(0, rd = rn + rm +!!(Cf>>31), rn, rm); // adc + if(opcode == 6*2+0) return sumf(0, rd = rn - rm - !(Cf>>31), rn,~rm); // sbc + if(opcode == 7*2+0) return sumf(0, rd = rm - rn - !(Cf>>31),~rn, rm); // rsc + if(opcode == 15*2+0) return bitf(0, rd = ~rm, rm); // mvn + + if(opcode == 3*2+1) return sumf(1, rd = rm - rn, ~rn, rm); // rsbs + if(opcode == 5*2+1) return sumf(1, rd = rn + rm +!!(Cf>>31), rn, rm); // adcs + if(opcode == 6*2+1) return sumf(1, rd = rn - rm - !(Cf>>31), rn,~rm); // sbcs + if(opcode == 7*2+1) return sumf(1, rd = rm - rn - !(Cf>>31),~rn, rm); // rscs + if(opcode == 15*2+1) return bitf(1, rd = ~rm, rm); // mvns +} + + + +uint32 ARMCore::oflow(uint32 rd, uint32 rn, uint32 rm) { + return ~(rn^rm) & (rn^rd); +} + +void ARMCore::bitf(bool s, uint32 rd, SOut rm) { + if(s) Cf = rm.carry, Nf = Zf = rd; +} + +void ARMCore::sumf(bool s, uint32 rd, uint32 rn, uint32 rm) { + if(s) Vf = oflow(rd,rn,rm), Cf = Vf ^ rd^rn^rm, Nf = Zf = rd; +} + + + +#include "arm.cpp" +#include "thumb.cpp" diff --git a/bsnes/nds/cpu/core.hpp b/bsnes/nds/cpu/core.hpp new file mode 100644 index 00000000..3838067d --- /dev/null +++ b/bsnes/nds/cpu/core.hpp @@ -0,0 +1,135 @@ + +struct ARMCore { + // Model specific implementation + virtual void power(); + virtual void step(unsigned n) = 0; + + // Instruction and data access + virtual uint32 fetch(uint32 addr, uint32 size, bool s) = 0; + virtual uint32 read(uint32 addr, uint32 size, bool s) = 0; + virtual void write(uint32 addr, uint32 size, bool s, uint32 data) = 0; + + // CDP, MCR, MRC + virtual void dataCop(uint4 cpno, uint4 op1, uint4 ird, uint4 irn, uint4 irm, uint4 op2) = 0; + + // Vectors + void reset() { vector(0x000, SVC); Ff = 1; } // THUMB: + void fiq() { vector(0x01c, FIQ); Ff = 1; if(spsr() & 1<<5) r[14] += 4; } // LR = insn+4 + void irq() { vector(0x018, IRQ); if(spsr() & 1<<5) r[14] += 4; } + void swi() { vector(0x008, SVC); if(spsr() & 1<<5) r[14] += 2; } // LR = insn+2 + void undefined() { vector(0x004, UND); if(spsr() & 1<<5) r[14] += 2; } + void pfabort() { vector(0x00c, ABT); if(spsr() & 1<<5) r[14] += 2; } + void abort() { vector(0x010, ABT); if(spsr() & 1<<5) r[14] += 8; } // LR = insn+8 + + // PSRs and mode switching + uint32& spsr(); + uint32 readCpsr(); + void writeCpsr(uint32 value, uint32 mask); + void vector(uint32 offset, unsigned tomode); + void swapBank(unsigned mode); + + alwaysinline bool evalCond(unsigned cond); + + void branch(bool tf, uint32 target); + + // LDR rotation, STR mirroring + uint32 load(uint32 addr, uint32 size); + void store(uint32 addr, uint32 size, uint32 data); + + // Shifts, arithmetic + struct SOut { + // Shifter output + uint32 rm; + int32 carry; + + SOut(uint32 rm) : rm(rm) {} + SOut(uint32 rm, int32 carry) : rm(rm), carry(carry) {} + operator uint32() { return rm; } + }; + alwaysinline SOut lsl(uint32 rm, uint8 rs); + alwaysinline SOut lsr(uint32 rm, uint8 rs); + alwaysinline SOut asr(uint32 rm, uint8 rs); + alwaysinline SOut ror(uint32 rm, uint8 rs); + alwaysinline SOut rrx(uint32 rm); + + alwaysinline SOut shiftImm(uint4 irm, uint2 opcode, uint5 rs); + alwaysinline void alu(unsigned opcode, uint32& rd, uint32 rn, SOut rm); + + // Flags + alwaysinline uint32 oflow(uint32 rd, uint32 rn, uint32 rm); + alwaysinline void bitf(bool s, uint32 rd, SOut rm); + alwaysinline void sumf(bool s, uint32 rd, uint32 rn, uint32 rm); + + // ARM argument Rm + alwaysinline uint32 armRm(uint4 irm) { return r[irm]; } + alwaysinline SOut armImmed(uint8 value, uint4 rs) { return ror(value, 2*rs); } + alwaysinline uint32 armOffset8(uint4 lo, uint4 hi) { return lo | hi<<4; } + alwaysinline uint32 armOffset12(uint12 value) { return value; } + + // ARM handlers + void armWritePsr(uint1 opcode, uint4 mask, uint32 rm); + void armReadPsr(uint1 opcode, uint4 ird); + void armBranch(uint1 link, uint1 exch, int26 offset); + void armBranchEx(uint1 link, uint4 irm); + void armClz(uint4 ird, uint4 irm); + void armDspAdd(uint2 opcode, uint4 ird, uint4 irn, uint4 irm); + void armDspMul(uint2 opcode, uint2 xy, uint4 ird, uint4 irn, uint4 irm, uint4 irs); + void armMultiply(uint4 opcode, uint4 ird, uint4 irn, uint4 irm, uint4 irs); + void armDataRs(uint5 opcode, uint4 ird, uint4 irn, uint4 irm, uint2 sh, uint4 irs); + void armData(uint5 opcode, uint4 ird, uint4 irn, SOut rm); + void armMemSwap(uint1 opcode, uint4 ird, uint4 irn, uint4 irm); + void armMem(uint5 opcode, uint4 ird, uint4 irn, uint32 rm); + void armMem_v4(uint5 opcode, uint2 sh, uint4 ird, uint4 irn, uint32 rm); + void armMem_v5(uint5 opcode, uint2 sh, uint4 ird, uint4 irn, uint32 rm); + void armBlock(uint5 opcode, uint4 irn, uint16 rlist); + + // THUMB handlers + void thumbDataLo(uint4 opcode, uint3 ird, uint3 irm); + void thumbDataHi(uint2 opcode, uint4 ird, uint4 irm); + void thumbDataImm(uint2 opcode, uint3 ird, uint8 rm); + void thumbShiftImm(uint2 opcode, uint3 ird, uint3 irm, uint5 rs); + void thumbAddSub(uint2 opcode, uint3 ird, uint3 irn, uint3 irm); + void thumbMemImm(uint5 opcode, uint3 ird, uint3 irn, uint5 rm); + void thumbMemReg(uint3 opcode, uint3 ird, uint3 irn, uint3 irm); + void thumbRelative(uint5 opcode, uint3 ird, uint8 rm); + void thumbAddSP(uint1 opcode, uint7 rm); + void thumbBlock(uint4 opcode, uint3 irn, uint8 rlist); + void thumbCond(uint4 opcode, int8 offset); + void thumbBranch(int11 offset); + void thumbBh(int11 offset); + void thumbBlx(uint1 link, uint11 offset); + + // CPSR + // NZCVQ are stored in a lazy format: + // - Z is only true when 0. + // - NCVQ are true when < 0 (bit 31 set). + int32 Nf, Zf, Cf, Vf, Qf; + uint8 If, Ff, Tf, mode; + + // Output from shifter + int32 carryout; // same format as Cf + + // Pipeline data + bool branched; + uint32 ifetch, idecode, iexecute; + + // Configuration + uint32 vectorBase; // Address of vector table + bool bxWithLoadedPC; // Does LDR/LDM PC behave as MOV or BX Rm? + + // Register banks + // - r_fiq[n] etc. hold registers in other banks. + // - r[n] holds registers for the active mode + // - This means that in FIQ mode, r_fiq[n] holds shadowed _user_ registers. + // - SPSR is not swapped, use spsr() to access it. + uint32 r[16], spsr_none, r_abt[2], spsr_abt; + uint32 r_fiq[7], spsr_fiq, r_irq[2], spsr_irq; + uint32 r_svc[2], spsr_svc, r_und[2], spsr_und; + + // Exception modes + enum { + USR = 0x10, + FIQ = 0x11, IRQ = 0x12, SVC = 0x13, + UND = 0x1b, ABT = 0x17, SYS = 0x1f, + }; +}; diff --git a/bsnes/nds/cpu/cpu.cpp b/bsnes/nds/cpu/cpu.cpp new file mode 100644 index 00000000..1b9dd4d1 --- /dev/null +++ b/bsnes/nds/cpu/cpu.cpp @@ -0,0 +1,337 @@ +#include +#include "bit.hpp" +#define imatch(bits) ((i & force< Bit::mask(bits) >()) \ + == force< Bit::binary(bits) >()) + +template static constexpr uint32 force() { return arg; } + +namespace NintendoDS { + +#include "core.cpp" +#include "disasm.cpp" + +ARM7TDMI arm7; +ARM946ES arm9; + + +CPUCore::CPUCore() { + thread = nullptr; +} + +CPUCore::~CPUCore() { + if(thread) co_delete(thread); +} + +void CPUCore::power() { + ARMCore::power(); + + clock = 0; + trace = false; + + powerState = running; + + config.xorSeeds[0] = 0; + config.xorSeeds[1] = 0; + config.slot2ramTiming = 0; + config.slot2romTiming0 = 0; + config.slot2romTiming1 = 0; + config.slot2phi = 0; + + interrupt.gate = false; + interrupt.enable = false; + interrupt.flags = 0; + + status.inVBlank = false; + status.inHBlank = false; + status.inVMatch = false; + status.irqOnVBlank = false; + status.irqOnHBlank = false; + status.irqOnVMatch = false; + status.vcompare = 0; + + msg.enable = false; + msg.irqOnRecv = false; + msg.irqOnSent = false; + msg.error = 0; + msg.empty = 1; + msg.full = 0; + msg.writeOffset = 0; + msg.readOffset = 0; + for(auto &e : msg.buffer) + e = 0; + + sync.enable = false; + sync.output = 0; + + event.irq = false; + event.anydma = false; + event.queue.reset(); + + for(unsigned n = 0; n < 4; n++) { + dma[n].enable = false; + dma[n].irq = false; + dma[n].size = 0; + dma[n].repeat = false; + dma[n].trigger = 0; + dma[n].srcStep = 0; + dma[n].destStep = 0; + dma[n].source = 0; + dma[n].dest = 0; + dma[n].count = 0; + dma[n].fill = 0; + dma[n].init.source = 0; + dma[n].init.dest = 0; + dma[n].init.count = 0; + + timer[n].enable = false; + timer[n].irq = false; + timer[n].cascade = false; + timer[n].divider = 0; + timer[n].reload = 0; + timer[n].count = 0; + timer[n].lastUpdate = 0; + timer[n].event.action = [&, n]() { updateTimer(n); }; + } +} + +void CPUCore::hdraw() { + status.inHBlank = false; + status.inVMatch = false; + + if(192 == video.line) { + status.inVBlank = true; + if(status.irqOnVBlank) + interrupt.flags |= irqVBlank; + + // Trigger vblank DMAs + dmaTrigger(0xf, 1); + } + if(262 == video.line) { + status.inVBlank = false; + } + + // Trigger peripheral-to-framebuffer DMA + if(config.arm9 && 2 <= video.line && video.line < 192+2) + dmaTrigger(0xf, 3); + + if(status.vcompare == video.line) { + status.inVMatch = true; + if(status.irqOnVMatch) { + interrupt.flags |= irqVMatch; + } + } +} + +void CPUCore::hblank() { + status.inHBlank = true; + if(status.irqOnHBlank) + interrupt.flags |= irqHBlank; + + // Trigger HDMAs + if(config.arm9 && video.line < 192) + dmaTrigger(0xf, 2); +} + + + +string CPUCore::tracePsr(uint32 value) { + return { value & 1<<31? "N":" ", + value & 1<<30? "Z":" ", + value & 1<<29? "C":" ", + value & 1<<28? "V":" ", + value & 1<<27? "Q":" ", + value & 1<< 7? "I":" ", + value & 1<< 6? "F":" ", + value & 1<< 5? "T":" ", + "/", hex<2>(value & 0x1f) }; +} + +void CPUCore::traceInsn() { + for(unsigned n = 0; n < 8; n++) print(hex<1>(n),":",hex<8>(r[n])," "); + + print(tracePsr(readCpsr()), "\n"); + + for(unsigned n = 8; n < 16; n++) print(hex<1>(n),":",hex<8>(r[n])," "); + + if(mode != SYS && mode != USR) print(tracePsr(spsr()), "\n"); + else print("--------:--", "\n"); + + if(Tf) print(hex<8>(r[15] - 4), ": ", hex<4>(iexecute), " ", disasm::thumb(this, iexecute), "\n"); + else print(hex<8>(r[15] - 8), ": ", hex<8>(iexecute), " ", disasm::arm(this, iexecute), "\n"); + + fflush(stdout); +} + + + +uint32 CPUCore::readReg(uint32 addr, uint32 size) { + addr &= ~3; + + //static bool vbl = 0; + switch(addr-0x04000000) { + case 0x0004: // Display status + return video.line << 16 | status.irqOnVMatch<< 5 | status.inVMatch<< 2 + | (status.vcompare & 0x0ff)<< 8 | status.irqOnHBlank<< 4 | status.inHBlank<< 1 + | (status.vcompare & 0x100)>> 1 | status.irqOnVBlank<< 3 | status.inVBlank<< 0; + + case 0x1004: + return 0; + + case 0x00b0: // DMA0 source + case 0x00bc: // DMA1 source + case 0x00c8: // DMA2 source + case 0x00d4: // DMA3 source + return regDmaSource((addr-0x40000b0)/12); + + case 0x00b4: // DMA0 dest + case 0x00c0: // DMA1 dest + case 0x00cc: // DMA2 dest + case 0x00d8: // DMA3 dest + return regDmaDest((addr-0x40000b0)/12); + + case 0x00b8: // DMA0 control + case 0x00c4: // DMA1 control + case 0x00d0: // DMA2 control + case 0x00dc: // DMA3 control + return regDmaControl((addr-0x40000b0)/12); + + case 0x00e0: // DMA0 fill + case 0x00e4: // DMA1 fill + case 0x00e8: // DMA2 fill + case 0x00ec: // DMA3 fill + return regDmaFill(addr>>2 & 3); + + case 0x0100: // Timer 0 + case 0x0104: // Timer 1 + case 0x0108: // Timer 2 + case 0x010c: // Timer 3 + return regTimer(addr>>2 & 3); + + case 0x130: { // Keypad input + unsigned keys = 0; + for(unsigned n = 0; n < 10; n++) { + if(interface->inputPoll(ID::Port::Buttons, 0, n)) + keys += 1<(addr),":",size,": unimplemented\n"); + return 0; +} + + + +void CPUCore::writeReg(uint32 addr, uint32 size, uint32 data) { + uint32 mask = 0xffffffff; + if(size == Half) mask = 0xffff << 8*(addr & 2); + if(size == Byte) mask = 0xff << 8*(addr & 3); + + addr &= ~3, data &= mask; + + switch(addr-0x04000000) { + case 0x0004: // Display status + // It might seem odd to have this here, but each CPU has one. + if(mask & 0xff00) status.vcompare = (status.vcompare & 0x100) | (data>>8 & 0x0ff); + if(mask & 0x0080) status.vcompare = (status.vcompare & 0x0ff) | (data<<1 & 0x100); + if(mask & 0x003f) { + status.irqOnVMatch = data >> 5; + status.irqOnHBlank = data >> 4; + status.irqOnVBlank = data >> 3; + } + return; + + case 0x1004: + return; + + case 0x00b0: // DMA0 source + case 0x00bc: // DMA1 source + case 0x00c8: // DMA2 source + case 0x00d4: // DMA3 source + return regDmaSource((addr-0x40000b0)/12, data, mask); + + case 0x00b4: // DMA0 dest + case 0x00c0: // DMA1 dest + case 0x00cc: // DMA2 dest + case 0x00d8: // DMA3 dest + return regDmaDest((addr-0x40000b0)/12, data, mask); + + case 0x00b8: // DMA0 control + case 0x00c4: // DMA1 control + case 0x00d0: // DMA2 control + case 0x00dc: // DMA3 control + return regDmaControl((addr-0x40000b0)/12, data, mask); + + case 0x00e0: // DMA0 fill + case 0x00e4: // DMA1 fill + case 0x00e8: // DMA2 fill + case 0x00ec: // DMA3 fill + return regDmaFill(addr>>2 & 3, data, mask); + + case 0x0100: // Timer 0 + case 0x0104: // Timer 1 + case 0x0108: // Timer 2 + case 0x010c: // Timer 3 + return regTimer(addr>>2 & 3, data, mask); + + case 0x132: // Keypad interrupt + break; + + // SYNC, message control, send port + case 0x0180: return regSync(data, mask); + case 0x0184: return regMsgControl(data, mask); + case 0x0188: return regMsgSend(data); + + // Slot 1 + case 0x01a0: return regSlot1Control(data, mask); + case 0x01a4: return regSlot1RomControl(data, mask); + case 0x01a8: return regSlot1RomCommand(0, data, mask); + case 0x01ac: return regSlot1RomCommand(1, data, mask); + case 0x01b0: return regSlot1RomSeed(0, data, mask); + case 0x01b4: return regSlot1RomSeed(1, data, mask); + case 0x01b8: return regSlot1RomSeed(2, data, mask); + + // IME, IE, IF + case 0x0208: if(mask & 1) interrupt.gate = data & 1; return; + case 0x0210: interrupt.enable = interrupt.enable & ~mask | data; return; + case 0x0214: interrupt.flags &= ~data; return; + case 0x0218: return; // IE: DSi bits + case 0x021c: return; // IF: DSi bits + } + //print("w ",hex<8>(addr),":",size," = ",hex<8>(data),": unimplemented\n"); +} + +#include "slot.cpp" +#include "message.cpp" +#include "dma.cpp" +#include "timer.cpp" +#include "arm7tdmi.cpp" +#include "arm946es.cpp" + +#undef imatch + +} diff --git a/bsnes/nds/cpu/cpu.hpp b/bsnes/nds/cpu/cpu.hpp new file mode 100644 index 00000000..061e4568 --- /dev/null +++ b/bsnes/nds/cpu/cpu.hpp @@ -0,0 +1,288 @@ +#include "core.hpp" + +struct CPUCore : ARMCore { + CPUCore(); + ~CPUCore(); + + void power(); + void hdraw(); + void hblank(); + + string tracePsr(uint32 value); + void traceInsn(); + + uint32 readReg(uint32 addr, uint32 size); + void writeReg(uint32 addr, uint32 size, uint32 data); + + void popMsg(); + void pushMsg(uint32 data); + void clearMsg(); + + uint32 regMsgControl(); + uint32 regMsgRecv(); + uint32 regSync(); + + void regMsgControl(uint32 data, uint32 mask); + void regMsgSend(uint32 data); + void regSync(uint32 data, uint32 mask); + + void dmaTransfer(unsigned no); + bool dmaTrigger(unsigned channels, unsigned value); + + uint32 regDmaControl(unsigned no); + uint32 regDmaSource(unsigned no); + uint32 regDmaDest(unsigned no); + uint32 regDmaFill(unsigned no); + + void regDmaControl(unsigned no, uint32 data, uint32 mask); + void regDmaSource(unsigned no, uint32 data, uint32 mask); + void regDmaDest(unsigned no, uint32 data, uint32 mask); + void regDmaFill(unsigned no, uint32 data, uint32 mask); + + void updateTimer(unsigned no); + uint32 regTimer(unsigned no); + void regTimer(unsigned no, uint32 data, uint32 mask); + + uint32 regSlot1Control(); + uint32 regSlot1RomControl(); + uint32 regSlot1RomCommand(unsigned index); + uint32 regSlot1RomRecv(); + + void regSlot1Control(uint32 data, uint32 mask); + void regSlot1RomControl(uint32 data, uint32 mask); + void regSlot1RomCommand(unsigned index, uint32 data, uint32 mask); + void regSlot1RomSeed(unsigned index, uint32 data, uint32 mask); + + uint32 regSlot2Control(); + void regSlot2Control(uint32 data, uint32 mask); + + enum { + // REG_IE, REG_IF bits + irqVBlank = 1<<0, irqHBlank = 1<<1, + irqVMatch = 1<<2, irqTimer = 1<<3, + irqClock = 1<<7, irqDma = 1<<8, + irqKeypad = 1<<12, irqSlot2 = 1<<13, + + irqSync = 1<<16, + irqMsgSent = 1<<17, irqMsgRecv = 1<<18, + irqCardDone = 1<<19, irqSlot1 = 1<<20, + irqGeomBuf = 1<<21, irqLid = 1<<22, + irqSpi = 1<<23, irqWifi = 1<<24, + }; + + struct { + bool arm7, arm9; + + uint64 xorSeeds[2]; + + uint2 slot2ramTiming; + uint2 slot2romTiming0; + uint1 slot2romTiming1; + uint2 slot2phi; + } config; + + struct { + bool gate; + uint32 enable, flags; + } interrupt; + + struct { + uint1 enable, irqOnRecv, irqOnSent; + uint1 error, empty, full; + uint4 writeOffset, readOffset; + uint32 buffer[16]; + } msg; + + struct { + uint1 enable; + uint4 output; + } sync; + + struct { + uint1 inVBlank, inHBlank, inVMatch; // vblank, hblank, line? + uint1 irqOnVBlank, irqOnHBlank, irqOnVMatch; // virq, hirq, lirq? + uint9 vcompare; // lineCompare? + } status; + + struct { + uint1 enable, irq, size, repeat; + uint3 trigger; + uint2 srcStep, destStep; + uint32 source, dest, count, fill; + struct { + uint32 source, dest, count; + } init; + } dma[4]; + + struct Timer { + uint1 enable, irq, cascade; + uint2 divider; + uint16 reload, count; + uint32 lastUpdate; + + Event event; + + uint32 regRead(); + void regWrite(uint32 data, uint32 mask); + void update(); + void operator()(); + } timer[4]; + + struct Ev { + bool irq; + bool anydma; + + EventQueue queue; + + Ev() : queue(60) {} + } event; + + bool trace; + uint32 insnLatch; + unsigned powerState; + enum { running, waiting, sleeping }; + + WordMemory bios; + + CPUCore* other; + + cothread_t thread; + int32 clock; +}; + + + +struct ARM7TDMI : CPUCore { + static void Thread(); + void main(); + void power(); + void step(unsigned clocks); + + alwaysinline void istep(unsigned clocks); + alwaysinline void execARM(); + alwaysinline void execTHUMB(); + + uint32 fetch(uint32 addr, uint32 size, bool s); + uint32 read(uint32 addr, uint32 size, bool s); + void write(uint32 addr, uint32 size, bool s, uint32 data); + void dataCop(uint4 cpno, uint4 op1, uint4 ird, uint4 irn, uint4 irm, uint4 op2); + + uint32 readReg(uint32 addr, uint32 size); + void writeReg(uint32 addr, uint32 size, uint32 data); + + ARM7TDMI(); + + struct SPI { + uint1 enable, hold, irq, size; + uint2 divider; // 4, 2, 1, 0.5 MHz + uint2 device; enum { power, flash, touch, none }; + uint16 data; + } spi; + + struct RTC { + uint4 in[2]; + uint4 out[2]; + uint4 dir[2]; + uint8 buffer; + uint3 index; + } rtc; + + struct SIO { + uint4 in, out, dir; + uint1 irq; + uint2 mode; + } sio; + + uint1 booted; + uint1 flag300; + + uint32 regSpi(); + void regSpi(uint32 data, uint32 mask); + + uint32 regRtc(); + void regRtc(uint32 data, uint32 mask); + + uint32 regSio(); + void regSio(uint32 data, uint32 mask); +}; + + + +struct ARM946ES : CPUCore { + SRAM itcm; + SRAM dtcm; + uint32 itcmRegion, itcmRCompare, itcmRMask, itcmWCompare, itcmWMask; + uint32 dtcmRegion, dtcmRCompare, dtcmRMask, dtcmWCompare, dtcmWMask; + + struct CR { + uint1 mmu; + uint1 dcache, icache; + uint1 endian; enum { little, big }; + uint1 cachePolicy; enum { random, roundRobin }; + uint1 dtcm, dtcmLoad; + uint1 itcm, itcmLoad; + } control; + + // Math functions + uint2 divMode; enum { div32, div64_32, div64 }; + uint1 divByZero; + uint1 divBusy; + int64 numerator; + int64 denominator; + int64 quotient; + int64 remainder; + + uint1 rootMode; enum { sqrt32, sqrt64 }; + uint1 rootBusy; + uint64 square; + uint32 squareRoot; + + uint1 booted; + uint1 flag300; + uint1 slot1access; + uint1 slot2access; + uint1 ramPriority; + + static void Thread(); + void main(); + void power(); + void step(unsigned clocks); + + alwaysinline void istep(unsigned clocks); + alwaysinline void execARM(); + alwaysinline void execTHUMB(); + + uint32 fetch(uint32 addr, uint32 size, bool s); + uint32 read(uint32 addr, uint32 size, bool s); + void write(uint32 addr, uint32 size, bool s, uint32 data); + void dataCop(uint4 cpno, uint4 op1, uint4 ird, uint4 irn, uint4 irm, uint4 op2); + + uint32 readReg(uint32 addr, uint32 size); + void writeReg(uint32 addr, uint32 size, uint32 data); + + void updateTcm(); + + void regDivideControl(uint32 data, uint32 mask); + void regNumerator(unsigned index, uint32 data, uint32 mask); + void regDenominator(unsigned index, uint32 data, uint32 mask); + void regSquareRootControl(uint32 data, uint32 mask); + void regSquare(unsigned index, uint32 data, uint32 mask); + + uint32 regDivideControl(); + uint32 regNumerator(unsigned index); + uint32 regDenominator(unsigned index); + uint32 regQuotient(unsigned index); + uint32 regRemainder(unsigned index); + uint32 regSquareRootControl(); + uint32 regSquare(unsigned index); + uint32 regSquareRoot(); + + void startDivide(); + void startSquareRoot(); + + ARM946ES(); +}; + + +extern ARM7TDMI arm7; +extern ARM946ES arm9; diff --git a/bsnes/nds/cpu/disasm.cpp b/bsnes/nds/cpu/disasm.cpp new file mode 100644 index 00000000..75cd55bf --- /dev/null +++ b/bsnes/nds/cpu/disasm.cpp @@ -0,0 +1,411 @@ +//#include "bit.hpp" +namespace disasm { + +#define collect(i, bits) (Bit::collect< Bit::field(bits) >((long)i)) +#define match(i, bits) ((i & force< Bit::mask(bits) >()) \ + == force< Bit::binary(bits) >()) + +template static constexpr uint32 force() { return arg; } + +static string conds[] = { + "eq","ne","cs","cc","mi","pl","vs","vc","hi","ls","ge","lt","gt","le","","" +}; +static string regs[] = { + "r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","sp","lr","pc" +}; +static string aluops[] = { + "and","eor","sub","rsb","add","adc","sbc","rsc","tst","teq","cmp","cmn","orr","mov","bic","mvn" +}; +static string shiftops[] = { + "lsl","lsr","asr","ror" +}; +static string blockops[] = { + "da","ia","db","ib" +}; + +string armAddr(uint2 index, uint4 rn, string u, string rm) { + if(index < 2) return {"[", regs[rn], "], ", u, rm}; + if(index == 2) return {"[", regs[rn], ", ", u, rm, "]"}; + if(index == 3) return {"[", regs[rn], ", ", u, rm, "]!"}; +} + +string armImmed(uint8 imm, uint4 rs) { + if(!rs) return {"#0x",hex<8>(imm)}; + if(imm & 0x03) return {"#0x",hex<8>(imm << 32-2*rs | imm >> 2*rs)}; + else return {"#0x",hex<2>(imm), ", ", 2*rs}; +} + +string armOffset8(uint4 lo, uint4 hi) { + return {"#0x",hex<2>(hi<<4 | lo)}; +} + +string armOffset12(uint12 offset) { + return {"#0x",hex<3>(offset)}; +} + +string armRm(uint4 rm) { + return regs[rm]; +} + +string armShiftImm(uint4 rm, uint2 sh, uint5 imm) { + if(sh==0 && imm==0) return regs[rm]; + if(sh==3 && imm==0) return {regs[rm], ", rrx"}; + return {regs[rm], ", ", shiftops[sh], " #", imm==0? 32u : (unsigned)imm}; +} + +string armShiftReg(uint4 rm, uint2 sh, uint4 rs) { + return {regs[rm], ", ", shiftops[sh], " ", regs[rs]}; +} + +string armUndefined(uint32 i) { + return {" #0x", hex<8>(i)}; +} + +string armBkpt(uint4 cc, uint12 hi, uint4 lo) { + return {"bkpt", conds[cc], " #0x", hex<4>(hi<<4 | lo)}; +} + +string armSwi(uint4 cc, uint24 immed) { + return {"swi", conds[cc], " #0x", hex<6>(immed)}; +} + +string armWritePsr(uint4 cc, uint1 psr, uint4 mask, string rm) { + string f = mask&8? "f":""; + string s = mask&4? "s":""; + string x = mask&2? "x":""; + string c = mask&1? "c":""; + return {"msr", conds[cc], " ", psr? "spsr":"cpsr", "_", f,s,x,c, ", ", rm}; +} + +string armReadPsr(uint4 cc, uint1 psr, uint4 rd) { + return {"mrs", conds[cc], " ", regs[rd], ", ", psr? "spsr":"cpsr"}; +} + +string armClz(uint4 cc, uint4 rd, uint4 rm) { + return {"clz", conds[cc], " ", regs[rd], ", ", regs[rm]}; +} + +string armDspAdd(uint4 cc, uint2 op, uint4 rd, uint4 rn, uint4 rm) { + string alu = op&1? "sub":"add"; + string d = op&2? "d":""; + return {"q",d,alu, conds[cc], " ", regs[rd], ", ", regs[rn], ", ", regs[rm]}; +} + +string armDspMul(uint4 cc, uint2 op, uint2 xy, uint4 rd, uint4 rn, uint4 rm, uint4 rs) { + string x = xy&1? "t":"b"; + string y = xy&2? "t":"b"; + + if(op==3) return {"smul",x,y, conds[cc], " ", regs[rd], ", ", regs[rm], ", ", regs[rs]}; + if(op==0) return {"smla",x,y, conds[cc], " ", regs[rd], ", ", regs[rm], ", ", regs[rs], ", ", regs[rn]}; + if(op==2) return {"smlal",x,y,conds[cc], " ", regs[rn], ", ", regs[rd], ", ", regs[rm], ", ", regs[rs]}; + + if(op==1 && (xy&1)) return {"smulw",y, conds[cc], " ", regs[rd], ", ", regs[rm], ", ", regs[rs]}; + if(op==1) return {"smlaw",y, conds[cc], " ", regs[rd], ", ", regs[rm], ", ", regs[rs], ", ", regs[rn]}; +} + +string armMultiply(uint4 cc, uint4 op, uint4 rd, uint4 rn, uint4 rm, uint4 rs) { + string s = op & 1? "s":""; + op &= ~1; + + if(op== 0) return {"mul", conds[cc], s, " ", regs[rd], ", ", regs[rm], ", ", regs[rs]}; + if(op== 2) return {"mla", conds[cc], s, " ", regs[rd], ", ", regs[rm], ", ", regs[rs], ", ", regs[rn]}; + + if(op== 8) return {"umull", conds[cc], s, " ", regs[rn], ", ", regs[rd], ", ", regs[rm], ", ", regs[rs]}; + if(op==10) return {"umlal", conds[cc], s, " ", regs[rn], ", ", regs[rd], ", ", regs[rm], ", ", regs[rs]}; + if(op==12) return {"smull", conds[cc], s, " ", regs[rn], ", ", regs[rd], ", ", regs[rm], ", ", regs[rs]}; + if(op==14) return {"smlal", conds[cc], s, " ", regs[rn], ", ", regs[rd], ", ", regs[rm], ", ", regs[rs]}; +} + +string armData(uint4 cc, uint5 op, uint4 rd, uint4 rn, string rm) { + string alu = aluops[collect(op, "aaaa.")]; + string s = collect(op, "....s")? "s" : ""; + + if(alu == "cmp" || alu == "cmn" || alu == "tst" || alu == "teq") + return {alu, conds[cc], s, " ", regs[rn], ", ", rm}; + + if(alu == "mov" || alu == "mvn" || rd == rn) + return {alu, conds[cc], s, " ", regs[rd], ", ", rm}; + + return {alu, conds[cc], s, " ", regs[rd], ", ", regs[rn], ", ", rm}; +} + +string armMem(uint4 cc, uint5 op, uint4 rd, uint4 rn, string rm) { + uint2 index = collect(op, "p..w."); + string u = collect(op, ".u...")? "" : "-"; + string b = collect(op, "..b..")? "b" : ""; + uint1 l = collect(op, "....l"); + + return {cc==15? "pld" : l? "ldr":"str", conds[cc], b, index==1?"t":"", + " ", regs[rd], ", ", armAddr(index, rn, u, rm)}; +} + +string armMem_v4(uint4 cc, uint5 op1, uint2 op2, uint4 rd, uint4 rn, string rm) { + uint2 index = collect(op1, "p..w."); + string u = collect(op1, ".u...")? "" : "-"; + uint1 l = collect(op1, "....l"); + string sh = op2==2?"sb" : op2==3?"sh" : "h"; + + return {l?"ldr":"str", conds[cc], sh, " ", regs[rd], ", ", armAddr(index, rn, u, rm)}; +} + +string armMem_v5(uint4 cc, uint5 op1, uint2 op2, uint4 rd, uint4 rn, string rm) { + uint2 index = collect(op1, "p..w."); + string u = collect(op1, ".u...")? "" : "-"; + uint1 s = op2 & 1; + + return {s?"str":"ldr", conds[cc], "d ", regs[rd], ", ", armAddr(index, rn, u, rm)}; +} + +string armMemSwap(uint4 cc, uint1 op, uint4 rd, uint4 rn, uint4 rm) { + string b = op? "b":""; + return {"swp", conds[cc], b, " ", regs[rm],", ", regs[rd], ", [", regs[rn], "]"}; +} + +string armMemCop(uint4 cc, uint4 cpno, uint5 op, uint4 rd, uint4 rn, uint8 offset) { + uint2 index = collect(op, "p..w."); + string u = collect(op, ".u...")? "" : "-"; + string n = collect(op, "..n..")? "l" : ""; + uint1 l = collect(op, "....l"); + + return {l? "ldc":"stc", conds[cc], cc==15?"2":"", n, " p",cpno, ", c",regs[rd], ", ", + armAddr(index, rn, index?u:"#", {"0x",hex<2>(offset)})}; +} + +string armBlock(uint4 cc, uint5 op, uint4 rn, uint16 rlist) { + uint2 index = collect(op, "pu..."); + string s = collect(op, "..s..")? "^" : ""; + string w = collect(op, "...w.")? "!" : ""; + uint1 l = collect(op, "....l"); + + string regnames = ""; + for(unsigned b = 0; b < 16; b++) { + if(rlist & 1<(target) + 2*link*exch}; +} + +string armBranchEx(uint4 cc, uint2 sh, uint4 rm) { + return {sh & 1? "blx":"bx", conds[cc], " ", regs[rm]}; +} + +string armCop(uint4 cc, uint4 cpno, uint4 op1, uint4 rd, uint4 rn, uint4 rm, uint4 op2) { + bool cdp = ~op2 & 1; + bool l = op1 & 1; + if(!cdp) op1 >>= 1; + op2 >>= 1; + return {cdp?"cdp" : l? "mrc":"mcr", conds[cc], cc==15?"2":"", + " p",cpno, ",", op1>>1, ", ", cdp?"cr":"r",rd, ", ", "cr",rn, ", ", "cr",rm, ", ", op2}; +} + +string armCop_v5(uint4 cc, uint4 cpno, uint4 op1, uint4 rd, uint4 rn, uint4 rm, uint4 op2) { + bool l = op1 & 1; + return {l? "mrrc":"mcrr", conds[cc], cc==15?"2":"", + " p",cpno, ",", op2, ", ", regs[rd], ", ", regs[rn], ", ", "cr",rm}; +} + + + +static string thumbmemregops[] = { + "str", "strh", "strb", "ldrsb", "ldr", "ldrh", "ldrb", "ldrsh" +}; +static string thumbmemimmops[] = { + "str", "ldr", "strb", "ldrb", "strh", "ldrh" +}; + +string thumbUndefined(uint16 i) { + return {" #0x", hex<4>(i)}; +} + +string thumbBkpt(uint8 imm) { + return {"bkpt #0x", hex<2>(imm)}; +} + +string thumbSwi(uint8 imm) { + return {"swi #0x", hex<2>(imm)}; +} + +string thumbAddSub(uint2 op, uint3 rd, uint3 rn, uint3 rm) { + if(op == 2 && rm == 0) return {"mov ", regs[rd], ", ", regs[rn]}; + if(op & 2) return {op & 1?"sub":"add", " ", regs[rd], ", ", regs[rn], ", #", rm}; + else return {op & 1?"sub":"add", " ", regs[rd], ", ", regs[rn], ", ", regs[rm]}; +} + +string thumbShiftImm(uint2 op, uint3 rd, uint3 rm, uint5 imm) { + return {shiftops[op], " ", regs[rd], ", ", regs[rm], ", #", op==0 || imm? (unsigned)imm : 32}; +} + +string thumbDataImm(uint2 op, uint3 rd, uint8 imm) { + if(op == 0) return {"mov ", regs[rd], ", #0x", hex<2>(imm)}; + if(op == 1) return {"cmp ", regs[rd], ", #0x", hex<2>(imm)}; + if(op == 2) return {"add ", regs[rd], ", #0x", hex<2>(imm)}; + if(op == 3) return {"sub ", regs[rd], ", #0x", hex<2>(imm)}; +} + +string thumbDataLo(uint4 op, uint3 rd, uint3 rm) { + if(op == 2) return {"lsl ", regs[rd], ", ", regs[rm]}; + if(op == 3) return {"lsr ", regs[rd], ", ", regs[rm]}; + if(op == 4) return {"asr ", regs[rd], ", ", regs[rm]}; + if(op == 7) return {"ror ", regs[rd], ", ", regs[rm]}; + if(op == 9) return {"neg ", regs[rd], ", ", regs[rm]}; + if(op ==13) return {"mul ", regs[rd], ", ", regs[rm]}; + + return {aluops[op], " ", regs[rd], ", ", regs[rm]}; +} + +string thumbDataHi(uint2 op, uint4 rd, uint4 rm) { + if(op == 0) return {"add ", regs[rd], ", ", regs[rm]}; + if(op == 1) return {"cmp ", regs[rd], ", ", regs[rm]}; + if(op == 2) return {"mov ", regs[rd], ", ", regs[rm]}; + if(rd & 8) return {"blx ", regs[rm]}; + else return {"bx ", regs[rm]}; +} + +string thumbMemReg(uint3 op, uint3 rd, uint3 rn, uint3 rm) { + return {thumbmemregops[op], " ", regs[rd], ", [", regs[rn], ", ", regs[rm], "]"}; +} + +string thumbMemImm(uint5 op, uint3 rd, uint3 rn, uint5 offset) { + unsigned rm = offset; + if(op < 14) rm *= 4; + if(op >= 16) rm *= 2; + + return {thumbmemimmops[op-12], " ", regs[rd], ", [", regs[rn], ", #0x", hex<3>(rm), "]"}; +} + +string thumbAddSP(uint1 op, uint7 offset) { + return {op?"sub":"add", " sp, #0x", hex<3>(4*offset)}; +} + +string thumbRelative(uint5 op, uint3 rd, uint8 offset) { + if(op == 9) return {"ldr ", regs[rd], ", [pc, #0x", hex<3>(4*offset), "]"}; + if(op ==18) return {"str ", regs[rd], ", [sp, #0x", hex<3>(4*offset), "]"}; + if(op ==19) return {"ldr ", regs[rd], ", [sp, #0x", hex<3>(4*offset), "]"}; + if(op ==20) return {"add ", regs[rd], ", pc, ", "#0x", hex<3>(4*offset)}; + if(op ==21) return {"add ", regs[rd], ", sp, ", "#0x", hex<3>(4*offset)}; +} + +string thumbBlock(uint4 op, uint3 rn, uint8 rlist) { + bool l = op & 1; + string regnames = ""; + for(unsigned b = 0; b < 8; b++) { + if(rlist & 1<(target)}; +} + +string thumbBranch(uint32 target) { + return {"b 0x", hex<8>(target)}; +} + +string thumbBh(int11 offset_hi) { + return {"bh 0x", hex<3>(2*offset_hi)}; +} + +string thumbBl(uint1 tbit, uint32 target) { + return {tbit? "bl":"blx", " 0x", hex<8>(target)}; +} + +string arm(ARMCore* arm, uint32 i) { + uint8 op = i>>20; + uint4 cc = i>>28; + uint4 rd = i>>12, rn = i>>16; + uint4 rm = i, rs = i>>8; + uint2 sh = i>>5; + uint32 pc = arm->r[15] & ~3; + + if(match(i, "1111 0101u101/// ..../")) return armMem(15, op, rd, rn, armOffset12(i)); + if(match(i, "1111 0111u101/// ...0/")) return armMem(15, op, rd, rn, armShiftImm(rm, sh, i>>7)); + if(match(i, "1111 101l..../// ..../")) return armBranch(14, 0, 1, pc + 4*int24(i)); + if(match(i, "1111 1100000l/// ..../")) return armUndefined(i); + if(match(i, "1111 1100010l/// ..../")) return armCop_v5(15, i>>8, op, rd, rn, rm, i>>4); + if(match(i, "1111 110punwl/// ..../")) return armMemCop(15, i>>8, op, rd, rn, i); + if(match(i, "1111 1110..../// ..../")) return armCop(15, i>>8, op, rd, rn, rm, i>>4); + if(match(i, "1111 ......../// ..../")) return armUndefined(i); + + if(match(i, ".... 00110r10/// ..../")) return armWritePsr(cc, i>>22, rn, armImmed(i, rs)); + if(match(i, ".... 00010r10/// 0000/")) return armWritePsr(cc, i>>22, rn, armRm(rm)); + if(match(i, ".... 00010r00/// 0000/")) return armReadPsr (cc, i>>22, rd); + if(match(i, ".... 00010010/// 00l1/")) return armBranchEx(cc, sh, rm); + if(match(i, ".... 00010010/// 0111/")) return armBkpt (cc, i>>8, i); + if(match(i, ".... 00010110/// 0001/")) return armClz (cc, rd, rm); + if(match(i, ".... 00010ds0/// 0101/")) return armDspAdd (cc, i>>21, rd, rn, rm); + if(match(i, ".... 00010oo0/// 1yx0/")) return armDspMul (cc, i>>21, sh, rn, rd, rm, rs); + + if(match(i, ".... 0000luas/// 1001/")) return armMultiply(cc, op, rn, rd, rm, rs); + if(match(i, ".... 00010b00/// 1001/")) return armMemSwap (cc, i>>22, rd, rn, rm); + if(match(i, ".... 0000ui1l/// 1sh1/")) return armUndefined(i); + if(match(i, ".... 000pu0w0/// 11s1/")) return armMem_v5 (cc, op, sh, rd, rn, armRm(i)); + if(match(i, ".... 000pu0wl/// 1sh1/")) return armMem_v4 (cc, op, sh, rd, rn, armRm(i)); + if(match(i, ".... 000pu1w0/// 11s1/")) return armMem_v5 (cc, op, sh, rd, rn, armOffset8(i, i>>8)); + if(match(i, ".... 000pu1wl/// 1sh1/")) return armMem_v4 (cc, op, sh, rd, rn, armOffset8(i, i>>8)); + + if(match(i, ".... 000aaaas/// 0sh1/")) return armData (cc, op, rd, rn, armShiftReg(rm, sh, rs)); + if(match(i, ".... 000aaaas/// .sh0/")) return armData (cc, op, rd, rn, armShiftImm(rm, sh, i>>7)); + if(match(i, ".... 001aaaas/// ..../")) return armData (cc, op, rd, rn, armImmed(i, rs)); + if(match(i, ".... 010pubwl/// ..../")) return armMem (cc, op, rd, rn, armOffset12(i)); + if(match(i, ".... 011pubwl/// ...0/")) return armMem (cc, op, rd, rn, armShiftImm(rm, sh, i>>7)); + + if(match(i, ".... 100puswl/// ..../")) return armBlock(cc, op, rn, i); + if(match(i, ".... 101l..../// ..../")) return armBranch(cc, i>>24, 0, pc + 4*int24(i)); + if(match(i, ".... 1100000l/// ..../")) return armUndefined(i); + if(match(i, ".... 1100010l/// ..../")) return armCop_v5(cc, i>>8, op, rd, rn, rm, i>>4); + if(match(i, ".... 110punwl/// ..../")) return armMemCop(cc, i>>8, op, rd, rn, i); + if(match(i, ".... 1110..../// ..../")) return armCop(cc, i>>8, op, rd, rn, rm, i>>4); + if(match(i, ".... 1111..../// ..../")) return armSwi(cc, i); + + return armUndefined(i); +} + +string thumb(ARMCore* arm, uint16 i) { + uint32 pc = arm->r[15] & ~1; + + if(match(i, "00011ismmmnnnddd")) return thumbAddSub (i>>9, i, i>>3, i>>6); + if(match(i, "000ssiiiiimmmddd")) return thumbShiftImm(i>>11, i, i>>3, i>>6); + if(match(i, "001oodddiiiiiiii")) return thumbDataImm (i>>11, i>>8, i); + if(match(i, "010000oooommmddd")) return thumbDataLo (i>>6, i, i>>3); + if(match(i, "010001oodmmmmddd")) return thumbDataHi (i>>8, (i&7)+(i>>4&8), i>>3); + + if(match(i, "0101ooommmnnnddd")) return thumbMemReg (i>>9, i, i>>3, i>>6); + if(match(i, "011bliiiiinnnddd")) return thumbMemImm (i>>11, i, i>>3, i>>6); + if(match(i, "1000liiiiinnnddd")) return thumbMemImm (i>>11, i, i>>3, i>>6); + + if(match(i, "10111110........")) return thumbBkpt(i); + if(match(i, "10110000siiiiiii")) return thumbAddSP ( i>>7, i); + if(match(i, "01001dddrrrrrrrr")) return thumbRelative(i>>11, i>>8, i); + if(match(i, "1001odddrrrrrrrr")) return thumbRelative(i>>11, i>>8, i); + if(match(i, "1010odddrrrrrrrr")) return thumbRelative(i>>11, i>>8, i); + + if(match(i, "11011110rrrrrrrr")) return thumbUndefined(i); + if(match(i, "11011111rrrrrrrr")) return thumbSwi(i); + if(match(i, "1101ccccrrrrrrrr")) return thumbCond ( i>>8, pc + 2*int8(i)); + if(match(i, "11100rrrrrrrrrrr")) return thumbBranch (pc + 2*int11(i)); + if(match(i, "11110rrrrrrrrrrr")) return thumbBh (i); + if(match(i, "11101rrrrrrrrrr1")) return thumbUndefined(i); + if(match(i, "111t1rrrrrrrrrrr")) return thumbBl (i>>12, arm->r[14] + 2*uint11(i)); + if(match(i, "1o..lnnnrrrrrrrr")) return thumbBlock (i>>11, i>>8, i); + + return thumbUndefined(i); +} + +#undef collect +#undef match +} diff --git a/bsnes/nds/cpu/dma.cpp b/bsnes/nds/cpu/dma.cpp new file mode 100644 index 00000000..f69363ec --- /dev/null +++ b/bsnes/nds/cpu/dma.cpp @@ -0,0 +1,131 @@ + +bool CPUCore::dmaTrigger(unsigned channels, unsigned value) { + for(unsigned no = 0; no < 4; no++) { + if((channels & 1<dma[no]; + + uint32 size = dma.size? Word : Half; + uint32 srcmask = config.arm7 && no == 0? 0x07fffffe : 0x0ffffffe; + uint32 destmask = config.arm7 && no < 3? 0x07fffffe : 0x0ffffffe; + uint32 countmask = 0x1fffff; + + if(config.arm7) + countmask = no < 3? 0x3fff : 0xffff; + + int srcinc = (dma.srcStep == 1? -2 : dma.srcStep != 2? +2 : 0); + int destinc = (dma.destStep == 1? -2 : dma.destStep != 2? +2 : 0); + + if(size == Word) + srcinc <<= 1, destinc <<= 1; + + do { + uint32 data = read(dma.source, size, true); + write(dma.dest, size, true, data); + + dma.source = (dma.source + srcinc) & srcmask; + dma.dest = (dma.dest + destinc) & destmask; + } while(--dma.count & countmask); + + if(dma.destStep == 3) dma.dest = dma.init.dest; + if(dma.repeat == 1) dma.count = dma.init.count; + if(dma.repeat == 0) dma.enable = false; + + if(dma.irq) interrupt.flags |= irqDma << no; +} + + +uint32 CPUCore::regDmaControl(unsigned no) { + return dma[no].init.count<<0 | dma[no].destStep<<21 | dma[no].srcStep<<23 + | dma[no].repeat<<25 | dma[no].size<<26 | dma[no].trigger<<27 + | dma[no].irq<<30 | dma[no].enable<<31; +} + +uint32 CPUCore::regDmaSource(unsigned no) { + return dma[no].init.source; +} + +uint32 CPUCore::regDmaDest(unsigned no) { + return dma[no].init.dest; +} + +uint32 CPUCore::regDmaFill(unsigned no) { + return dma[no].fill; +} + +void CPUCore::regDmaControl(unsigned no, uint32 data, uint32 mask) { + auto &dma = this->dma[no]; + + uint32 countmask = 0x1fffff; + if(config.arm7) // still limited to 16K / 64K transfers + countmask = no < 3? 0x3fff : 0xffff; + + if(mask & countmask) { + dma.init.count ^= (dma.init.count ^ data) & countmask; + } + if(mask & 0xffe00000) { // ?? + bool previously = dma.enable; + + dma.destStep = data>>21; + dma.srcStep = data>>23; + dma.repeat = data>>25; + dma.size = data>>26; + dma.trigger = data>>27; + dma.irq = data>>30; + dma.enable = data>>31; + + if(config.arm7) + dma.trigger >>= 1; + + if(dma.enable) { + if(previously == false) { + // Latch new settings + dma.source = dma.init.source; + dma.dest = dma.init.dest; + dma.count = dma.init.count; + } + if(dma.trigger == 0) { + dmaTransfer(no); + } + else if(dma.trigger == 7) { + // Geometry fifo - DMA display list + // - just do it right here since we lack timing + dmaTransfer(no); + } + //else { + // print(config.arm7?"arm7":"arm9", + // ": dma trigger ",dma.trigger,": unimplemented\n"); + //} + } + } +} + +void CPUCore::regDmaSource(unsigned no, uint32 data, uint32 mask) { + mask &= 0x0ffffffe; + if(config.arm7 && no == 0) + mask &= 0x07fffffe; // DMA0 is internal only + + dma[no].init.source ^= (dma[no].init.source ^ data) & mask; +} + +void CPUCore::regDmaDest(unsigned no, uint32 data, uint32 mask) { + mask &= 0x0ffffffe; + if(config.arm7 && no != 3) + mask &= 0x07fffffe; // only DMA3 can write to slot 2 + + dma[no].init.dest ^= (dma[no].init.dest ^ data) & mask; +} + +void CPUCore::regDmaFill(unsigned no, uint32 data, uint32 mask) { + if(config.arm7) + return; // not present + + dma[no].fill ^= (dma[no].fill ^ data) & mask; +} diff --git a/bsnes/nds/cpu/math.cpp b/bsnes/nds/cpu/math.cpp new file mode 100644 index 00000000..f7ec1bd4 --- /dev/null +++ b/bsnes/nds/cpu/math.cpp @@ -0,0 +1,115 @@ + +void ARM946ES::regDivideControl(uint32 data, uint32 mask) { + if(mask & 3) divMode = data; + startDivide(); +} + +void ARM946ES::regNumerator(unsigned index, uint32 data, uint32 mask) { + int64 update = data & mask; update <<= 32*index; + int64 umask = mask; umask <<= 32*index; + + numerator ^= (numerator ^ update) & umask; + startDivide(); +} + +void ARM946ES::regDenominator(unsigned index, uint32 data, uint32 mask) { + int64 update = data & mask; update <<= 32*index; + int64 umask = mask; umask <<= 32*index; + + denominator ^= (denominator ^ update) & umask; + startDivide(); +} + + + +void ARM946ES::regSquareRootControl(uint32 data, uint32 mask) { + if(mask & 1) rootMode = data; + startSquareRoot(); +} + +void ARM946ES::regSquare(unsigned index, uint32 data, uint32 mask) { + int64 update = data & mask; update <<= 32*index; + int64 umask = mask; umask <<= 32*index; + + square ^= (square ^ update) & umask; + startSquareRoot(); +} + + + +uint32 ARM946ES::regDivideControl() { + return divMode<<0 | divByZero<<13 | divBusy<<15; +} + +uint32 ARM946ES::regNumerator(unsigned index) { + return numerator >> 32*index; +} + +uint32 ARM946ES::regDenominator(unsigned index) { + return denominator >> 32*index; +} + +uint32 ARM946ES::regQuotient(unsigned index) { + return quotient >> 32*index; +} + +uint32 ARM946ES::regRemainder(unsigned index) { + return remainder >> 32*index; +} + + + +uint32 ARM946ES::regSquareRootControl() { + return rootMode<<0 | rootBusy<<15; +} + +uint32 ARM946ES::regSquare(unsigned index) { + return square >> 32*index; +} + +uint32 ARM946ES::regSquareRoot() { + return squareRoot; +} + + + +void ARM946ES::startDivide() { + divByZero = false; + + int64 n = numerator, d = denominator; + + if(divMode == div32) { n &= 0xffffffffll; n -= 2*(n & 1ll<<31); } + if(divMode != div64) { d &= 0xffffffffll; d -= 2*(d & 1ll<<31); } + + // Ugh, GBATEK does not say at all how remainder works with signed values. + // Will have to fix this later.. + if(d == 0) { + divByZero = true; + quotient = n >= 0? -1 : +1; + remainder = n; + } + else if(n == (-1ll<<63) && d == -1ll) { + quotient = -1ll<<63; + } + else { + quotient = n / d; + remainder = n % d; + } +} + + + +void ARM946ES::startSquareRoot() { + uint64 x = square, r = 0; + if(rootMode == sqrt32) + x = uint32(x); + + for(uint64 bit = 1ull << 62; bit != 0; bit >>= 2) { + r >>= 1; + if(x >= 2*r + bit) { + x -= 2*r + bit; + r += bit; + } + } + squareRoot = r; +} diff --git a/bsnes/nds/cpu/message.cpp b/bsnes/nds/cpu/message.cpp new file mode 100644 index 00000000..16f7c554 --- /dev/null +++ b/bsnes/nds/cpu/message.cpp @@ -0,0 +1,98 @@ + +void CPUCore::popMsg() { + msg.full = false; + if(++msg.readOffset == msg.writeOffset) + msg.empty = true; +} + +void CPUCore::pushMsg(uint32 data) { + msg.buffer[msg.writeOffset] = data; + msg.empty = false; + if(++msg.writeOffset == msg.readOffset) + msg.full = true; +} + +void CPUCore::clearMsg() { + msg.readOffset = 0; + msg.writeOffset = 0; + msg.empty = true; + msg.full = false; + for(unsigned n = 0; n < 16; n++) + msg.buffer[n] = 0; +} + +uint32 CPUCore::regMsgControl() { + return msg.enable<<15 | msg.error<<14 + | msg.irqOnRecv<<10 | other->msg.full<<9 | other->msg.empty<<8 + | msg.irqOnSent<<2 | this->msg.full<<1 | this->msg.empty<<0; +} + +void CPUCore::regMsgControl(uint32 data, uint32 mask) { + if(mask & 0x00ff) { + bool previously = msg.irqOnSent; + + msg.irqOnSent = data>>2; + if(data & 1<<3) clearMsg(); + + // Edge triggered + if(msg.empty && msg.irqOnSent && previously == false) { + interrupt.flags |= irqMsgSent; + } + } + if(mask & 0xff00) { + bool previously = msg.irqOnRecv; + + msg.irqOnRecv = data>>10; + msg.enable = data>>15; + if(data & 1<<14) msg.error = false; + + // Edge triggered + if(!other->msg.empty && msg.irqOnRecv && previously == false) + interrupt.flags |= irqMsgRecv; + } +} + +void CPUCore::regMsgSend(uint32 data) { + if(msg.enable) { + if(msg.full) { + msg.error = true; + return; + } + bool wasEmpty = msg.empty; + pushMsg(data); + + if(wasEmpty && other->msg.irqOnRecv) + other->interrupt.flags |= irqMsgRecv; + } +} + +uint32 CPUCore::regMsgRecv() { + uint32 data = other->msg.buffer[other->msg.readOffset]; + + if(other->msg.enable) { + if(other->msg.empty) { + msg.error = true; + return data; + } + other->popMsg(); + + if(other->msg.empty && other->msg.irqOnSent) + other->interrupt.flags |= irqMsgSent; + } + return data; +} + +uint32 CPUCore::regSync() { + return sync.enable<<14 | this->sync.output<<8 | other->sync.output<<0; +} + +void CPUCore::regSync(uint32 data, uint32 mask) { + if(mask & 0xff00) { + sync.enable = data>>14; + sync.output = data>>8; + if(data & 1<<13) { + if(other->sync.enable) + other->interrupt.flags |= irqSync; + } + } +} diff --git a/bsnes/nds/cpu/slot.cpp b/bsnes/nds/cpu/slot.cpp new file mode 100644 index 00000000..ebd7c600 --- /dev/null +++ b/bsnes/nds/cpu/slot.cpp @@ -0,0 +1,131 @@ + +uint32 CPUCore::regSlot1Control() { + return slot1.spi.baud<<0 | slot1.spi.hold<<6 + | slot1.spi.busy<<7 | slot1.spi.enable<<13 + | slot1.transferIrq<<14 | slot1.enable<<15 + | slot1.spi.data<<16; +} + +uint32 CPUCore::regSlot1RomControl() { + return slot1.decryptLatency<<0 | slot1.xorData<<13 + | slot1.responseLatency<<16 | slot1.xorCmds<<22 + | slot1.dataReady<<23 | slot1.blockSize<<24 + | slot1.clock<<27 | slot1.secureMode<<28 + | 1<<29 | slot1.transferPending<<31; +} + +uint32 CPUCore::regSlot1RomCommand(unsigned index) { + auto cmd = slot1.command; + if(index == 0) cmd >>= 32; + + return (cmd>>24 & 0xff) << 0 + | (cmd>>16 & 0xff) << 8 + | (cmd>> 8 & 0xff) << 16 + | (cmd>> 0 & 0xff) << 24; +} + +uint32 CPUCore::regSlot1RomRecv() { + uint32 data = 0; + data += slot1.readRom() << 0; + data += slot1.readRom() << 8; + data += slot1.readRom() << 16; + data += slot1.readRom() << 24; + return data; +} + +void CPUCore::regSlot1Control(uint32 data, uint32 mask) { + if(mask & 0x000000ff) { + slot1.spi.baud = data>>0; + slot1.spi.hold = data>>6; + } + if(mask & 0x0000ff00) { + slot1.spi.enable = data>>13; + slot1.transferIrq = data>>14; + slot1.enable = data>>15; + + if(slot1.enable == false || slot1.spi.enable == false) { + if(slot1.card && slot1.card->spi) { + //print("slot1 spi: deselect\n"); + slot1.card->spi->select(false); + } + } + } + if(mask & 0x00ff0000) { + // SPI transfer + if(!slot1.spi.enable) return; + slot1.spi.data = slot1.spiTransfer(data>>16); + //print("slot1 spi: w ",hex<2>(data>>16)," r ",hex<2>(slot1.spi.data),"\n"); + } +} + +void CPUCore::regSlot1RomControl(uint32 data, uint32 mask) { + if(mask & 0x00001fff) { + slot1.decryptLatency ^= (slot1.decryptLatency ^ data) & mask; + } + if(mask & 0x0000e000) { + slot1.xorData = data>>13; + if(data & 1<<15) { + slot1.lfsr[0] = config.xorSeeds[0]; + slot1.lfsr[1] = config.xorSeeds[1]; + } + } + if(mask & 0x00ff0000) { + slot1.responseLatency = data>>16; + slot1.xorCmds = data>>22; + } + if(mask & 0xff000000) { + slot1.blockSize = data>>24; + slot1.clock = data>>27; + slot1.secureMode = data>>28; + if(data & 1<<31) + slot1.startRomTransfer(); + } +} + +void CPUCore::regSlot1RomCommand(unsigned index, uint32 data, uint32 mask) { + auto &cmd = slot1.command; + uint64 ldata = data; + + // Big endian commands, argh! + if(index == 0) { + if(mask & 0x000000ff) cmd ^= (cmd ^ ldata<<56) & 0xff00000000000000; + if(mask & 0x0000ff00) cmd ^= (cmd ^ ldata<<40) & 0x00ff000000000000; + if(mask & 0x00ff0000) cmd ^= (cmd ^ ldata<<24) & 0x0000ff0000000000; + if(mask & 0xff000000) cmd ^= (cmd ^ ldata<< 8) & 0x000000ff00000000; + } else { + if(mask & 0x000000ff) cmd ^= (cmd ^ ldata<<24) & 0x00000000ff000000; + if(mask & 0x0000ff00) cmd ^= (cmd ^ ldata<< 8) & 0x0000000000ff0000; + if(mask & 0x00ff0000) cmd ^= (cmd ^ ldata>> 8) & 0x000000000000ff00; + if(mask & 0xff000000) cmd ^= (cmd ^ ldata>>24) & 0x00000000000000ff; + } +} + +void CPUCore::regSlot1RomSeed(unsigned index, uint32 data, uint32 mask) { + if(index == 2) { + data &= 0x7f007f & mask; + if(mask & 0x00007f) config.xorSeeds[0] = (config.xorSeeds[0] & 0xffffffff) | uint64(data>>0 )<<32; + if(mask & 0x7f0000) config.xorSeeds[1] = (config.xorSeeds[1] & 0xffffffff) | uint64(data>>16)<<32; + } + else { + config.xorSeeds[index] ^= (config.xorSeeds[index] ^ data) & mask; + } +} + + + +uint32 CPUCore::regSlot2Control() { + return config.slot2ramTiming<<0 | config.slot2romTiming0<<2 + | config.slot2romTiming1<<4 | config.slot2phi<<5 + | !arm9.slot2access<<7 | !arm9.slot1access<<11 + | 1<<13 | 1<<14 | !arm9.ramPriority<<15; +} + +void CPUCore::regSlot2Control(uint32 data, uint32 mask) { + if(mask & 0xff) { + config.slot2ramTiming = data>>0; + config.slot2romTiming0 = data>>2; + config.slot2romTiming1 = data>>4; + config.slot2phi = data>>5; + } +} + diff --git a/bsnes/nds/cpu/thumb.cpp b/bsnes/nds/cpu/thumb.cpp new file mode 100644 index 00000000..50ec31ce --- /dev/null +++ b/bsnes/nds/cpu/thumb.cpp @@ -0,0 +1,150 @@ + +void ARMCore::thumbShiftImm(uint2 opcode, uint3 ird, uint3 irm, uint5 rs) { + auto &rd = r[ird]; + r[15] += 2; + + SOut r = shiftImm(irm, opcode, rs); + bitf(true, rd = r, r); // lsl, lsr, asr +} + +void ARMCore::thumbAddSub(uint2 opcode, uint3 ird, uint3 irn, uint3 irm) { + auto& rd = r[ird], rn = r[irn], rm = opcode & 2? (uint32)irm : r[irm]; + r[15] += 2; + + if(opcode & 1) sumf(true, rd = rn-rm, rn, ~rm); // subs + else sumf(true, rd = rn+rm, rn, rm); // adds +} + +void ARMCore::thumbDataImm(uint2 opcode, uint3 ird, uint8 rm) { + auto &rd = r[ird], rn = rd; + r[15] += 2; + + if(opcode == 0) bitf(true, rd = rm, {rm, Cf}); // movs + if(opcode == 1) sumf(true, rn-rm, rn, ~rm); // cmps + if(opcode == 2) sumf(true, rd = rn+rm, rn, rm); // adds + if(opcode == 3) sumf(true, rd = rn-rm, rn, ~rm); // subs +} + +void ARMCore::thumbDataLo(uint4 opcode, uint3 ird, uint3 irm) { + auto &rd = r[ird], rm = r[irm]; + r[15] += 2; + + if(opcode == 2) { SOut r = lsl(rd, rm); bitf(true, rd = r, r); } // lsls + else if(opcode == 3) { SOut r = lsr(rd, rm); bitf(true, rd = r, r); } // lsrs + else if(opcode == 4) { SOut r = asr(rd, rm); bitf(true, rd = r, r); } // asrs + else if(opcode == 7) { SOut r = ror(rd, rm); bitf(true, rd = r, r); } // rors + else if(opcode == 9) sumf(true, rd = -rm, 0, ~rm); // negs + else if(opcode == 13) bitf(true, rd = rm * rd, {rm*rd, Cf}); // muls + else alu(2*opcode+1, rd, rd, {rm,Cf}); // others are same as ARM +} + +void ARMCore::thumbDataHi(uint2 opcode, uint4 ird, uint4 irm) { + auto &rd = r[ird], rn = rd, rm = r[irm]; + r[15] += 2; + + if(opcode == 0) rd = rn + rm; // add + if(opcode == 1) sumf(true, rn-rm, rn, ~rm); // cmps + if(opcode == 2) rd = rm; // mov + if(opcode == 3) { // bx, blx + if(ird & 8) r[14] = r[15] - 4 + 1; + return branch(rm & 1, rm); + } + if(ird == 15) branch(1, r[15]); +} + +void ARMCore::thumbMemImm(uint5 opcode, uint3 ird, uint3 irn, uint5 rm) { + auto &rd = r[ird], addr = r[irn]; + r[15] += 2; + + if(opcode == 13) rd = load(addr + 4*rm, Word); // ldr + if(opcode == 15) rd = load(addr + 1*rm, Byte); // ldrb + if(opcode == 17) rd = load(addr + 2*rm, Half); // ldrh + if(opcode == 12) store(addr + 4*rm, Word, rd); // str + if(opcode == 14) store(addr + 1*rm, Byte, rd); // strb + if(opcode == 16) store(addr + 2*rm, Half, rd); // strh +} + +void ARMCore::thumbMemReg(uint3 opcode, uint3 ird, uint3 irn, uint3 irm) { + bool ld = opcode & 1; + auto &rd = r[ird], addr = r[irn] + r[irm]; + r[15] += 2; + + if(opcode == 0) store(addr, Word, rd); // str + if(opcode == 1) store(addr, Half, rd); // strh + if(opcode == 2) store(addr, Byte, rd); // strb + if(opcode == 4) rd = load(addr, Word); // ldr + if(opcode == 5) rd = load(addr, Half); // ldrh + if(opcode == 6) rd = load(addr, Byte); // ldrb + if(opcode == 7) rd = (int16) load(addr, Half); // ldrsh + if(opcode == 3) rd = (int8) load(addr, Byte); // ldrsb +} + +void ARMCore::thumbRelative(uint5 opcode, uint3 ird, uint8 rm) { + auto &rd = r[ird], pc = r[15] & ~3; + r[15] += 2; + + if(opcode == 9) rd = load(pc + 4*rm, Word); // ldr [pc,#n] + if(opcode ==18) store(r[13] + 4*rm, Word, rd); // str [sp,#n] + if(opcode ==19) rd = load(r[13] + 4*rm, Word); // ldr [sp,#n] + if(opcode ==20) rd = pc + 4*rm; // adr rd,pc,.. + if(opcode ==21) rd = r[13] + 4*rm; // adr rd,sp,.. +} + +void ARMCore::thumbAddSP(uint1 opcode, uint7 rm) { + r[15] += 2; + if(opcode == 0) r[13] += 4*rm; // add sp,#n + if(opcode == 1) r[13] -= 4*rm; // sub sp,#n +} + +void ARMCore::thumbBlock(uint4 opcode, uint3 irn, uint8 rlist) { + auto &rn = opcode < 8? r[13] : r[irn]; + bool ld = opcode & 1; + bool up = true; + bool writeback = true; + uint32 regs = rlist; + + if(opcode < 8) { + up = ld; + if(irn & 1) regs |= (1 << 14+ld); + } + + uint32 addr = rn, base = rn, size = 4*bit::count(regs); + if(!up) addr -= size; + r[15] += 2; + + for(unsigned b = 0, s = 0; b < 16; b++) { + if(~regs & 1<timer[no]; + + if(timer.cascade == false) + updateTimer(no); + + return timer.count<<0 | timer.divider<<16 + | timer.cascade<<18 | timer.irq<<22 | timer.enable<<23; +} + +void CPUCore::regTimer(unsigned no, uint32 data, uint32 mask) { + auto &timer = this->timer[no]; + + if(timer.cascade == false) + updateTimer(no); + + event.queue.remove(timer.event); + + if(mask & 0x00ffff) { + timer.reload ^= (timer.reload ^ data) & mask; + } + if(mask & 0xff0000) { + if(!timer.enable && (data & 1<<23)) { + timer.count = timer.reload; + } + timer.divider = data>>16; + timer.cascade = data>>18; + timer.irq = data>>22; + timer.enable = data>>23; + } + + if(timer.cascade == false) + updateTimer(no); +} + +void CPUCore::updateTimer(unsigned no) { + auto &timer = this->timer[no]; + + if(timer.enable) { + uint16 old = timer.count; + uint32 ticks = 1; + + unsigned dbits[] = { 1, 7, 9, 11 }; // 33MHz, 512KHz, 128KHz, 32KHz + unsigned s = dbits[timer.divider]; + uint32 divider = 1 << s; + + if(timer.cascade) { + timer.count++; + } else { + ticks = (event.queue.time >> s) - (timer.lastUpdate >> s); + timer.count += ticks; + } + + if(ticks && timer.count <= old) { + if(timer.irq) interrupt.flags |= irqTimer << no; + + timer.count = timer.reload; + + if(no < 3 && this->timer[no+1].cascade) + updateTimer(no+1); + } + + if(timer.cascade == false) { + uint32 ticksLeft = 0x10000 - timer.count; + uint32 nextTick = divider;// - (event.queue.time & divider-1); + uint32 nextOverflow = nextTick + divider * (ticksLeft-1); + + // The above commented part breaks maxmod's interpolated audio + // - perhaps the internal counters have expanded? + if(event.queue.time & 1) + nextTick -= 1; // align to 33MHz clock however + + event.queue.add(nextOverflow, timer.event); + } + } + timer.lastUpdate = event.queue.time; +} diff --git a/bsnes/nds/gpu/commands.cpp b/bsnes/nds/gpu/commands.cpp new file mode 100644 index 00000000..530c47e9 --- /dev/null +++ b/bsnes/nds/gpu/commands.cpp @@ -0,0 +1,527 @@ + +bool GPU::gxMatrixMode() { + if(numArgs < 1) return false; + + matrixMode = args[0]; + return true; +} + +bool GPU::gxMatrixPush() { + if(matrixMode == mmTexture) { + return true; + } + if(matrixMode == mmProjection) { + projStack[0] = projMatrix; + if(projSP++ == 1) { stackOverflow = true; } + return true; + } + // mmModelView or mmLitView + lightStack[viewSP % 32] = lightMatrix; + viewStack[viewSP % 32] = viewMatrix; + + if(viewSP++ >= 31) { stackOverflow = true; } + return true; +} + +bool GPU::gxMatrixPop() { + if(numArgs < 1) return false; + + if(matrixMode == mmTexture) { + return true; + } + if(matrixMode == mmProjection) { + if(projSP-- == 0) { stackOverflow = true; } + projMatrix = projStack[0]; + return true; + } + // mmModelView or mmLitView + args[0] %= 64; + viewSP -= args[0]; + if(viewSP >= 31) { stackOverflow = true; } + + lightMatrix = lightStack[viewSP % 32]; + viewMatrix = viewStack[viewSP % 32]; + return true; +} + +bool GPU::gxMatrixStore() { + if(numArgs < 1) return false; + + if(matrixMode == mmTexture) { + return true; + } + if(matrixMode == mmProjection) { + projStack[0] = projMatrix; + return true; + } + // mmModelView or mmLitView + args[0] %= 32; + if(args[0] == 31) { stackOverflow = true; } + + lightStack[args[0]] = lightMatrix; + viewStack[args[0]] = viewMatrix; + return true; +} + +bool GPU::gxMatrixRestore() { + if(numArgs < 1) return false; + + if(matrixMode == mmTexture) { + return true; + } + if(matrixMode == mmProjection) { + projMatrix = projStack[0]; + clipMatrix = projMatrix; + transform(clipMatrix, viewMatrix); + return true; + } + // mmModelView or mmLitView + args[0] %= 32; + if(args[0] == 31) { stackOverflow = true; } + + lightMatrix = lightStack[args[0]]; + viewMatrix = viewStack[args[0]]; + clipMatrix = projMatrix; + transform(clipMatrix, viewMatrix); + return true; +} + +bool GPU::gxMatrixLoadIdentity() { + loadMatrix({ 0x1000, 0, 0, 0, + 0, 0x1000, 0, 0, + 0, 0, 0x1000, 0, + 0, 0, 0, 0x1000 }); + return true; +} + +// Storage is transposed to make each row contiguous, which is opposite +// of OpenGL. This allows easy multiplication with column vectors. + +bool GPU::gxMatrixLoad4x4() { + if(numArgs < 16) return false; + + loadMatrix({ args[ 0], args[ 4], args[ 8], args[12], + args[ 1], args[ 5], args[ 9], args[13], + args[ 2], args[ 6], args[10], args[14], + args[ 3], args[ 7], args[11], args[15] }); + return true; +} + +bool GPU::gxMatrixLoad4x3() { + if(numArgs < 12) return false; + + loadMatrix({ args[ 0], args[ 3], args[ 6], args[ 9], + args[ 1], args[ 4], args[ 7], args[10], + args[ 2], args[ 5], args[ 8], args[11], + 0, 0, 0, 0x1000 }); + return true; +} + +bool GPU::gxMatrixMult4x4() { + if(numArgs < 16) return false; + + multMatrix({ args[ 0], args[ 4], args[ 8], args[12], + args[ 1], args[ 5], args[ 9], args[13], + args[ 2], args[ 6], args[10], args[14], + args[ 3], args[ 7], args[11], args[15] }); + return true; +} + +bool GPU::gxMatrixMult4x3() { + if(numArgs < 12) return false; + + multMatrix({ args[ 0], args[ 3], args[ 6], args[ 9], + args[ 1], args[ 4], args[ 7], args[10], + args[ 2], args[ 5], args[ 8], args[11], + 0, 0, 0, 0x1000 }); + return true; +} + +bool GPU::gxMatrixRotate() { + if(numArgs < 9) return false; + + multMatrix({ args[0], args[3], args[6], 0, + args[1], args[4], args[7], 0, + args[2], args[5], args[8], 0, + 0, 0, 0, 0x1000 }); + return true; +} + +bool GPU::gxMatrixScale() { + if(numArgs < 3) return false; + + // Don't scale the lighting matrix + unsigned prevMode = matrixMode; + if(matrixMode == mmLitView) + matrixMode = mmModelView; + + multMatrix({ args[0], 0, 0, 0, + 0, args[1], 0, 0, + 0, 0, args[2], 0, + 0, 0, 0, 0x1000 }); + matrixMode = prevMode; + return true; +} + +bool GPU::gxMatrixTranslate() { + if(numArgs < 3) return false; + + multMatrix({ 0x1000, 0, 0, args[0], + 0, 0x1000, 0, args[1], + 0, 0, 0x1000, args[2], + 0, 0, 0, 0x1000 }); + return true; +} + + + +void GPU::unpackColor(int32* color, uint16 rgb) { + // Yes, it's really this crazy. PPU and GPU colors do NOT match! + // Super annoying when trying to hide things or make them seamless. + int r = 2*(rgb>> 0 & 31); r += (r>0); + int g = 2*(rgb>> 5 & 31); g += (g>0); + int b = 2*(rgb>>10 & 31); b += (b>0); + + color[0] = 0x1000*r; + color[1] = 0x1000*g; + color[2] = 0x1000*b; +} + +bool GPU::gxColor() { + if(numArgs < 1) return false; + + unpackColor(vertex.color, args[0]); + return true; +} + +bool GPU::gxNormal() { + if(numArgs < 1) return false; + + // Normalize to +/- 1 range + normal[0] = int10(args[0]>> 0) << 3; + normal[1] = int10(args[0]>>10) << 3; + normal[2] = int10(args[0]>>20) << 3; + normal[3] = 0; + + if(primitive.texTransform == PS::ttNormal) { + // Used for environment mapping. + textureMatrix(0,3) = vertex.texCoord[0]; + textureMatrix(1,3) = vertex.texCoord[1]; + + vertex.texCoord[0] = normal[0]; + vertex.texCoord[1] = normal[1]; + vertex.texCoord[2] = normal[2]; + vertex.texCoord[3] = 0x1000; + + transform(textureMatrix, vertex.texCoord); + } + + transform(lightMatrix, normal); + + vertex.color = emission; + + for(auto& light : lights) { + if(light.enable == false) + continue; + + int32 dl = max(0, -dot(light.eyeVector, normal)); + int32 sl = max(0, -dot(light.halfVector, normal)); + + sl = min(0xfff, sl*sl / 0x1000); + if(useShineTable) + sl = shininess[sl>>5] << 4; + + for(unsigned n = 0; n < 3; n++) { + vertex.color[n] += (int64) specular[n] * light.color[n] * sl / 0x8000000; + vertex.color[n] += (int64) diffuse[n] * light.color[n] * dl / 0x8000000; + vertex.color[n] += (int64) ambient[n] * light.color[n] * 0x200 / 0x8000000; // ?? + } + } + return true; +} + +bool GPU::gxTexCoord() { + if(numArgs < 1) return false; + + vertex.texCoord[0] = 0x1000 * int16(args[0]>> 0); + vertex.texCoord[1] = 0x1000 * int16(args[0]>>16); + vertex.texCoord[2] = 0x1000; + vertex.texCoord[3] = 0x1000; + + // Affine texture transformations + if(primitive.texTransform == PS::ttTexCoord) + transform(textureMatrix, vertex.texCoord); + + //if(primitive.texTransform == PS::ttNormal || primitive.texTransform == PS::ttVertex) { + // // Plug in U,V for environment/vertex mapping + // textureMatrix(0,3) = vertex.texCoord[0]; + // textureMatrix(1,3) = vertex.texCoord[1]; + //} + return true; +} + +bool GPU::gxVertex3i_16() { + if(numArgs < 2) return false; + + // 4.12, +/- 16 range + vertex.position[0] = int16(args[0]>> 0); + vertex.position[1] = int16(args[0]>>16); + vertex.position[2] = int16(args[1]>> 0); + submitVertex(); + return true; +} + +bool GPU::gxVertex3i_10() { + if(numArgs < 1) return false; + + // 4.6, +/- 16 range + vertex.position[0] = int10(args[0]>> 0) << 6; + vertex.position[1] = int10(args[0]>>10) << 6; + vertex.position[2] = int10(args[0]>>20) << 6; + submitVertex(); + return true; +} + +bool GPU::gxVertex2i_XY() { + if(numArgs < 1) return false; + + // Use same Z as before + vertex.position[0] = int16(args[0]>> 0); + vertex.position[1] = int16(args[0]>>16); + submitVertex(); + return true; +} + +bool GPU::gxVertex2i_XZ() { + if(numArgs < 1) return false; + + // Use same Y as before + vertex.position[0] = int16(args[0]>> 0); + vertex.position[2] = int16(args[0]>>16); + submitVertex(); + return true; +} + +bool GPU::gxVertex2i_YZ() { + if(numArgs < 1) return false; + + // Use same X as before + vertex.position[1] = int16(args[0]>> 0); + vertex.position[2] = int16(args[0]>>16); + submitVertex(); + return true; +} + +bool GPU::gxVertex3i_Rel() { + if(numArgs < 1) return false; + + // 0.10, previous vertex +/- 0.125 relative range + vertex.position[0] = int16(vertex.position[0] + int10(args[0]>> 0)); + vertex.position[1] = int16(vertex.position[1] + int10(args[0]>>10)); + vertex.position[2] = int16(vertex.position[2] + int10(args[0]>>20)); + submitVertex(); + return true; +} + + + +bool GPU::gxAttribute() { + if(numArgs < 1) return false; + + for(unsigned n = 0; n < 4; n++) + lights[n].enable = args[0] >> n; + + attributes = args[0]; + return true; +} + +bool GPU::gxTexImage() { + if(numArgs < 1) return false; + + texImage = args[0] & 0x3fffffff; + primitive.texTransform = args[0] >> 30; + + //if(primitive.type == PS::tris || primitive.type == PS::quads) + // primitive.texImage = texImage; + return true; +} + +bool GPU::gxTexPalette() { + if(numArgs < 1) return false; + + texPalette = args[0] & 0x1fff; + + //if(primitive.type == PS::tris || primitive.type == PS::quads) + // primitive.texPalette = texPalette; + return true; +} + + + +bool GPU::gxLightDiffuseAmbient() { + if(numArgs < 1) return false; + + unpackColor(diffuse, args[0] >> 0); + unpackColor(ambient, args[0] >> 16); + + // This is meant to allow display lists to be ignorant of + // the lighting state (namely whether it's in use or not). + if(args[0] & 1<<15) + unpackColor(vertex.color, args[0]); + return true; +} + +bool GPU::gxLightSpecularEmission() { + if(numArgs < 1) return false; + + unpackColor(specular, args[0] >> 0); + unpackColor(emission, args[0] >> 16); + + useShineTable = args[0] & 1<<15; + return true; +} + +bool GPU::gxLightDirection() { + if(numArgs < 1) return false; + + unsigned no = args[0] >> 30; + auto &light = lights[no]; + + light.direction[0] = int10(args[0] >> 0); + light.direction[1] = int10(args[0] >>10); + light.direction[2] = int10(args[0] >>20); + light.direction[3] = 0; + + light.eyeVector = light.direction; + transform(lightMatrix, light.eyeVector); + + light.halfVector[0] = (light.eyeVector[0] + 0)/2; + light.halfVector[1] = (light.eyeVector[1] + 0)/2; + light.halfVector[2] = (light.eyeVector[2] - 0x1000)/2; + light.halfVector[3] = 0; + return true; +} + +bool GPU::gxLightColor() { + if(numArgs < 1) return false; + + unsigned no = args[0] >> 30; + + unpackColor(lights[no].color, args[0]); + return true; +} + +bool GPU::gxLightShininess() { + if(numArgs < 32) return false; + + for(unsigned n = 0; n < 128; n += 4) { + shininess[n+0] = args[n/4] >> 0; + shininess[n+1] = args[n/4] >> 8; + shininess[n+2] = args[n/4] >> 16; + shininess[n+3] = args[n/4] >> 24; + } + return true; +} + + + +bool GPU::gxBeginPrimitive() { + if(numArgs < 1) return false; + + if(uploadList->numPrims < 2048 + && primitive.size >= (primitive.type==PS::quadStrip? 4 : 3)) + uploadList->numPrims++; // terminate the preceding strip + + primitive.type = args[0]; + primitive.size = 0; + primitive.winding = 0; + primitive.attributes = attributes; + primitive.texImage = texImage; + primitive.texPalette = texPalette; + return true; +} + +bool GPU::gxSwapBuffers() { + if(numArgs < 1) return false; + + sceneFinished = true; + swapArgument = args[0]; + return true; +} + +bool GPU::gxViewport() { + if(numArgs < 1) return false; + + viewport.x = (args[0]>> 0 & 0xff) + 0; + viewport.y = (args[0]>> 8 & 0xff) + 0; + viewport.w = (args[0]>>16 & 0xff) + 1 - viewport.x; + viewport.h = (args[0]>>24 & 0xff) + 1 - viewport.y; + return true; +} + + + +bool GPU::gxCullTest() { + if(numArgs < 3) return false; + + // Box range given as x, y, z, w, h, d + int16 a[6] = { + int16(args[0]>> 0), int16(args[0]>>16), int16(args[1]>> 0), + int16(args[1]>>16), int16(args[2]>> 0), int16(args[2]>>16), + }; + // -> l, b, n, r, t, f + a[3] += a[0]; a[4] += a[1]; a[5] += a[2]; + + // Generate all 8 corners and outcodes + int32 out[8]; + ClipSpaceVertex vertex[8] = { // X Y Z + {{ a[0], a[1], a[2], 0x1000 }}, // l,b,n + {{ a[0], a[1], a[5], 0x1000 }}, // l,b,f + {{ a[0], a[4], a[2], 0x1000 }}, // l,t,n + {{ a[0], a[4], a[5], 0x1000 }}, // l,t,f + {{ a[3], a[1], a[2], 0x1000 }}, // r,b,n + {{ a[3], a[1], a[5], 0x1000 }}, // r,b,f + {{ a[3], a[4], a[2], 0x1000 }}, // r,t,n + {{ a[3], a[4], a[5], 0x1000 }}, // r,t,f + }; + for(unsigned n = 0; n < 8; n++) { + transform(clipMatrix, vertex[n].position); + out[n] = outcode(vertex[n]); + } + + // Find out which sides of the box would be drawn + bool front = (out[0] & out[2] & out[4] & out[6]) == 0; + bool back = (out[1] & out[3] & out[5] & out[7]) == 0; + bool bottom = (out[0] & out[1] & out[4] & out[5]) == 0; + bool top = (out[2] & out[3] & out[6] & out[7]) == 0; + bool left = (out[0] & out[1] & out[2] & out[3]) == 0; + bool right = (out[4] & out[5] & out[6] & out[7]) == 0; + + // True if at least one face was accepted + boxResult = front || back || bottom || top || left || right; + return true; +} + +bool GPU::gxPositionTest() { + if(numArgs < 2) return false; + + vertex.position[0] = int16(args[0]>> 0); + vertex.position[1] = int16(args[0]>>16); + vertex.position[2] = int16(args[1]>> 0); + + vertexResult = vertex.position; + transform(clipMatrix, vertexResult); + return true; +} + +bool GPU::gxDirectionTest() { + if(numArgs < 1) return false; + + normalResult[0] = int10(args[0]>> 0) << 3; + normalResult[1] = int10(args[0]>>10) << 3; + normalResult[2] = int10(args[0]>>20) << 3; + normalResult[3] = 0; + + transform(lightMatrix, normalResult); + return true; +} diff --git a/bsnes/nds/gpu/commands.hpp b/bsnes/nds/gpu/commands.hpp new file mode 100644 index 00000000..032f0c12 --- /dev/null +++ b/bsnes/nds/gpu/commands.hpp @@ -0,0 +1,41 @@ + + bool gxMatrixMode(); + bool gxMatrixPush(); + bool gxMatrixPop(); + bool gxMatrixStore(); + bool gxMatrixRestore(); + bool gxMatrixLoadIdentity(); + bool gxMatrixLoad4x4(); + bool gxMatrixLoad4x3(); + bool gxMatrixMult4x4(); + bool gxMatrixMult4x3(); + bool gxMatrixRotate(); + bool gxMatrixScale(); + bool gxMatrixTranslate(); + + bool gxColor(); + bool gxNormal(); + bool gxTexCoord(); + bool gxVertex3i_16(); + bool gxVertex3i_10(); + bool gxVertex2i_XY(); + bool gxVertex2i_XZ(); + bool gxVertex2i_YZ(); + bool gxVertex3i_Rel(); + bool gxAttribute(); + bool gxTexImage(); + bool gxTexPalette(); + + bool gxLightDiffuseAmbient(); + bool gxLightSpecularEmission(); + bool gxLightDirection(); + bool gxLightColor(); + bool gxLightShininess(); + + bool gxBeginPrimitive(); + bool gxSwapBuffers(); + bool gxViewport(); + + bool gxCullTest(); + bool gxPositionTest(); + bool gxDirectionTest(); diff --git a/bsnes/nds/gpu/geometry.cpp b/bsnes/nds/gpu/geometry.cpp new file mode 100644 index 00000000..51a52f08 --- /dev/null +++ b/bsnes/nds/gpu/geometry.cpp @@ -0,0 +1,316 @@ + +void GPU::submitVertex() { + if(primitive.texTransform == PS::ttVertex) { + textureMatrix(0,3) = vertex.texCoord[0]; + textureMatrix(1,3) = vertex.texCoord[1]; + + vertex.texCoord[0] = vertex.position[0]; + vertex.texCoord[1] = vertex.position[1]; + vertex.texCoord[2] = vertex.position[2]; + vertex.texCoord[3] = 0x1000; + + transform(textureMatrix, vertex.texCoord); + } + + auto &v = primitive.v; + auto input = vertex; + + transform(clipMatrix, input.position); + + switch(primitive.type) { + case PS::tris: + v[primitive.size] = input; + + if(++primitive.size >= 3) + submitTri(v[0], v[1], v[2]); + break; + + case PS::triStrip: + v[min(2, primitive.size)] = input; + + if(++primitive.size >= 3) { + submitTriStrip(v[0], v[1], v[2]); + primitive.winding ^= 1; + v[0] = v[1]; + v[1] = v[2]; + } + break; + + case PS::quads: + v[primitive.size] = input; + + // Slightly different order than triangles and strips + if(++primitive.size >= 4) + submitQuad(v[0], v[1], v[2], v[3]); + break; + + case PS::quadStrip: + if(primitive.size % 2) v[min(3, primitive.size)] = input; + else v[min(2, primitive.size)] = input; + + if(++primitive.size >= 4) { + if(primitive.size % 2 == 0) { + submitQuadStrip(v[0], v[1], v[2], v[3]); + v[0] = v[2]; + v[1] = v[3]; + } + } + break; + } +} + + + +void GPU::submitTri(ClipSpaceVertex& v0, ClipSpaceVertex& v1, ClipSpaceVertex& v2) { + int32 out[] = { outcode(v0), outcode(v1), outcode(v2) }; + int32 face = facing(v0, v1, v2); + + if(primitive.winding == 1) + face = -face; // this can happen when clipping triangle strips + + bool front = primitive.attributes & PS::drawFront; + bool back = primitive.attributes & PS::drawBack; + + bool culled = face && !(front && face > 0 || back && face < 0); + bool clipped = out[0] | out[1] | out[2]; + bool reject = out[0] & out[1] & out[2] | culled; + + if(!reject) { + ClipSpaceVertex *vs[] = { &v0, &v1, &v2 }; + addPoly(vs, 3, clipped); + } + primitive.texImage = texImage; + primitive.texPalette = texPalette; + primitive.size = 0; +} + +void GPU::submitQuad(ClipSpaceVertex& v0, ClipSpaceVertex& v1, ClipSpaceVertex& v2, ClipSpaceVertex& v3) { + int32 out[] = { outcode(v0), outcode(v1), outcode(v2), outcode(v3) }; + int32 face = facing(v0, v1, v2); + + bool front = primitive.attributes & PS::drawFront; + bool back = primitive.attributes & PS::drawBack; + + bool culled = face && !(front && face > 0 || back && face < 0); + bool clipped = out[0] | out[1] | out[2] | out[3]; + bool reject = out[0] & out[1] & out[2] & out[3] | culled; + + if(!reject) { + ClipSpaceVertex *vs[] = { &v0, &v1, &v2, &v3 }; + addPoly(vs, 4, clipped); + } + primitive.texImage = texImage; + primitive.texPalette = texPalette; + primitive.size = 0; +} + + + +void GPU::submitTriStrip(ClipSpaceVertex& v0, ClipSpaceVertex& v1, ClipSpaceVertex& v2) { + int32 face = facing(v0, v1, v2); + + if(primitive.winding == 1) + face = -face; + + // Clipping is a pain here. The easiest way that comes to mind is to check + // whether a vertex was clipped. Then if so, split this polygon off and, + // after clipping, restart the primitive with the current winding order. + bool front = primitive.attributes & PS::drawFront; + bool back = primitive.attributes & PS::drawBack; + + bool culled = face != 0 && !(front && face > 0 || back && face < 0); + bool clipped = outcode(v0) | outcode(v1) | outcode(v2); + + if(culled || clipped) { + if(uploadList->numPrims < 2048 && primitive.size > 3) + uploadList->numPrims++; // Terminate the current strip (if any) + + submitTri(v0, v1, v2); // Submit as separate triangle + primitive.size = 2; // Next vertex restarts the strip + return; + } + if(primitive.size == 3) { + addPrim(Prim::triStrip); + addVertex(v0); + addVertex(v1); + } + addVertex(v2); +} + +void GPU::submitQuadStrip(ClipSpaceVertex& v0, ClipSpaceVertex& v1, ClipSpaceVertex& v2, ClipSpaceVertex& v3) { + int32 face = facing(v0, v1, v3); + bool front = primitive.attributes & PS::drawFront; + bool back = primitive.attributes & PS::drawBack; + + bool culled = face != 0 && !(front && face > 0 || back && face < 0); + bool clipped = outcode(v0) | outcode(v1) | outcode(v2) | outcode(v3); + + if(culled || clipped) { + if(uploadList->numPrims < 2048 && primitive.size > 4) + uploadList->numPrims++; // Terminate the current strip (if any) + + submitQuad(v0, v1, v3, v2); // Submit as separate quad + primitive.size = 2; // Next two vertices restart the strip + return; + } + if(primitive.size == 4) { + addPrim(Prim::quadStrip); + addVertex(v0); + addVertex(v1); + } + addVertex(v2); + addVertex(v3); +} + +bool GPU::addPoly(ClipSpaceVertex **v, unsigned numVerts, bool clip) { + struct Entry { + ClipSpaceVertex v; unsigned out; + Entry() {} + Entry(const ClipSpaceVertex& s) : v(s), out(outcode(s)) {} + operator ClipSpaceVertex() const { return v; } + }; + + vector list[2], *in = list+0, *out = list+1; + + for(unsigned i = 0; i < numVerts; i++) + out->append({ *(v[i]) }); + + if(clip) { + for(unsigned plane = 0; plane < 6; plane++) { + const int axis = plane/2, side = plane%2? +1 : -1; + + std::swap(in, out); + out->reset(); + + for(unsigned i = 0; i < in->size(); ) { + auto &a = (*in)[i++]; + auto &b = (*in)[i % in->size()]; + + if(1<append({ clipEdge(b, a, axis, side) }); + if(1<append({ clipEdge(a, b, axis, side) }); + else out->append({ b }); + } + } + } + if(!out->size()) + return true; + + if(!addPrim(Prim::poly)) + return false; + + for(unsigned i = 0; i < out->size(); i++) + addVertex((*out)[i]); + + uploadList->numPrims++; + return true; +} + +bool GPU::addVertex(const ClipSpaceVertex &v) { + if(uploadList->numPrims == 2048 || uploadList->numVerts == 6144) + return false; + + // XYZ are all in range +/-w in homogenous coordinates + uploadList->prims[uploadList->numPrims].numVerts++; + auto &out = uploadList->verts[uploadList->numVerts++]; + + // xyzw = 20.12 + // uv = 20.12 (in texels) + // rgb = 20.12 (0 - 63.0) + int32 w = v.position[3]; + + // Perspective transformation - divide everything by W. + // This flattens the perspective and allows linear pixel interpolation. + out.w = w? w : 1; // still needed to restore UVZ and RGB. + out.x = (int64) v.position[0] * 0x40000000/w; // x/w + out.y = (int64) v.position[1] * 0x40000000/w; // y/w + out.z = (int64) v.position[2] * 0x40000000/w; // z/w + out.u = (int64) v.texCoord[0] * 0x4000/w; // u/w + out.v = (int64) v.texCoord[1] * 0x4000/w; // v/w + out.r = (int64) v.color[0] * 0x4000/w; // r/w + out.g = (int64) v.color[1] * 0x4000/w; // g/w + out.b = (int64) v.color[2] * 0x4000/w; // b/w + + // Apply viewport scaling. X and Y get rounded off somehow. Vertices and + // interpolants jump around a lot, despite being perspective correct. :( + out.x = (out.x + 0x40000000ll) * viewport.w/2 + 0x400000*viewport.x >> 8; + out.y = (out.y + 0x40000000ll) * viewport.h/2 + 0x400000*viewport.y >> 8; + + // With perspective projections, W is a linear function of Z. Default then + // is to use the nonlinear Z/W, giving more precision close up. This setting + // gives linear depth values instead. + // + // Note: In orthographic/2D views, Z/W is linear anyway because W=1. In that + // case this option kills Z buffering (kinda bad, given the auto Y sort). + //if(uploadList->depthUseW) + // out.z = max(-0x8000, min(0x7fff, w)); // ? + return true; +} + +bool GPU::addPrim(unsigned shape) { + if(uploadList->numPrims == 2048) + return false; + + auto &out = uploadList->prims[uploadList->numPrims]; + + //primitive.texImage = texImage; + //primitive.texPalette = texPalette; + + out.numVerts = 0; + out.firstVert = uploadList->numVerts; + out.id = primitive.attributes >> 24 & 63; + out.alpha = primitive.attributes >> 16 & 31; + out.drawMode = shape; + out.drawMode += Prim::fog * uint1(primitive.attributes >> 15); + out.drawMode += Prim::zequal * uint1(primitive.attributes >> 14); + out.drawMode += Prim::zwrite * uint1(primitive.attributes >> 11); + out.drawMode += Prim::shadeMask & uint2(primitive.attributes >> 4); + out.drawMode += Prim::colorKey * uint1(primitive.texImage >> 29); + + out.texFormat = primitive.texImage >> 26 & 7; + //out.texSize[1] = primitive.texImage >> 23 & 7; + //out.texSize[0] = primitive.texImage >> 20 & 7; + //out.texBorder[1] = primitive.texImage >> 17 & 5; + //out.texBorder[0] = primitive.texImage >> 16 & 5; + out.texImage = primitive.texImage; + out.texPalette = primitive.texPalette; + if(out.texFormat != Prim::I2) + out.texPalette *= 2; + + return true; +} + + +// Matrices, OpenGL style: +// +// clip projection view.. model.. vertex +// |Cx| |0 4 8 c| |0 4 8 c| |0 4 8 c| |Vx| +// |Cy| = |1 5 9 d| * |1 5 9 d| * |1 5 9 d| * |Vy| +// |Cz| |2 6 a e| |2 6 a e| |2 6 a e| |Vz| +// |Cw| |3 7 b f| |3 7 b f| |3 7 b f| |Vw| +// +// transform() multiplies new matrix on the LEFT, ie. m = t*m. + +void GPU::loadMatrix(const Matrix& m) { + if(matrixMode == mmTexture) textureMatrix = m; + else { + if(matrixMode == mmLitView) lightMatrix = m; + if(matrixMode == mmProjection) projMatrix = m; + else /*mmModelView,mmLitView*/ viewMatrix = m; + + clipMatrix = projMatrix; + transform(clipMatrix, viewMatrix); + } +} + +void GPU::multMatrix(const Matrix& m) { + if(matrixMode == mmTexture) transform(textureMatrix, m); + else { + if(matrixMode == mmLitView) transform(lightMatrix, m); + if(matrixMode == mmProjection) transform(projMatrix, m); + else /*mmModelView,mmLitView*/ transform(viewMatrix, m); + + clipMatrix = projMatrix; + transform(clipMatrix, viewMatrix); + } +} diff --git a/bsnes/nds/gpu/geometry.hpp b/bsnes/nds/gpu/geometry.hpp new file mode 100644 index 00000000..fb48cc84 --- /dev/null +++ b/bsnes/nds/gpu/geometry.hpp @@ -0,0 +1,83 @@ + + uint32 regGeomStatus(); + uint32 regGeomLoad(); + uint32 regGeomPosition(unsigned index); + uint32 regGeomNormal(unsigned index); + uint32 regClipMatrix(unsigned index); + uint32 regLightMatrix(unsigned index); + + void regGeomMaxPointDepth(uint32 data, uint32 mask); + void regGeomStatus(uint32 data, uint32 mask); + + + void loadMatrix(const Matrix& m); + void multMatrix(const Matrix& m); + + void unpackColor(int32* color, uint16 rgb); + + void submitVertex(); + void submitTriStrip(ClipSpaceVertex& v0, ClipSpaceVertex& v1, ClipSpaceVertex& v2); + void submitQuadStrip(ClipSpaceVertex& v0, ClipSpaceVertex& v1, ClipSpaceVertex& v2, ClipSpaceVertex& v3); + void submitTri(ClipSpaceVertex& v0, ClipSpaceVertex& v1, ClipSpaceVertex& v2); + void submitQuad(ClipSpaceVertex& v0, ClipSpaceVertex& v1, ClipSpaceVertex& v2, ClipSpaceVertex& v3); + + bool addPoly(ClipSpaceVertex **v, unsigned numVerts, bool clip); + bool addVertex(const ClipSpaceVertex &v); + bool addPrim(unsigned shape); + + struct Light { + uint1 enable; + Vector color; + Vector direction; + + Vector eyeVector; + Vector halfVector; + }; + + // Matrix state + uint2 matrixMode; enum { mmProjection, mmModelView, mmLitView, mmTexture }; + bool stackOverflow; + uint1 projSP; + uint6 viewSP; + Matrix clipMatrix; + Matrix textureMatrix; + Matrix projMatrix, projStack[1]; + Matrix viewMatrix, viewStack[32]; + Matrix lightMatrix, lightStack[32]; + + Vector vertexResult; + Vector normalResult; + bool boxResult; + + // Lighting and material state + Light lights[4]; + Vector normal; + Vector diffuse; + Vector ambient; + Vector specular; + Vector emission; + uint8 shininess[128]; + bool useShineTable; + + // Primitive state + struct PS { + unsigned size; + uint1 winding; + uint2 type; enum { tris, quads, triStrip, quadStrip }; + uint32 attributes; enum { drawFront = 0x80, drawBack = 0x40 }; + + uint32 texImage; + uint16 texPalette; + uint2 texTransform; enum { ttNone, ttTexCoord, ttNormal, ttVertex }; + + ClipSpaceVertex v[4]; + } primitive; + + uint32 attributes; + uint32 texImage; + uint16 texPalette; + ClipSpaceVertex vertex; + + struct { + unsigned x, y, w, h; + } viewport; diff --git a/bsnes/nds/gpu/gpu.cpp b/bsnes/nds/gpu/gpu.cpp new file mode 100644 index 00000000..6911f6c2 --- /dev/null +++ b/bsnes/nds/gpu/gpu.cpp @@ -0,0 +1,497 @@ +#include + +namespace NintendoDS { + +GPU gpu; + + +GPU::GPU() { } + +void GPU::power() { + powered = true; + swapArgument = 0; + uploadList = &sceneList[0]; + renderList = &sceneList[1]; + renderedLines = 0; + stencilMode = false; + sceneFinished = false; + commandBufIrq = false; + packedCommands = 0; + numArgs = 0; + + for(unsigned n = 0; n < 2; n++) { + sceneList[n].numVerts = 0; + sceneList[n].numPrims = 0; + sceneList[n].firstAlpha = 0; + sceneList[n].alphaSort = 1; + sceneList[n].depthUseW = 0; + + memset(sceneList[n].verts, 0, sizeof sceneList[n].verts); + memset(sceneList[n].prims, 0, sizeof sceneList[n].prims); + } + + // Geometry state + Matrix identity = { + 0x1000, 0,0,0, + 0, 0x1000, 0,0, + 0,0, 0x1000, 0, + 0,0,0, 0x1000, + }; + clipMatrix = identity; projSP = viewSP = stackOverflow = 0; + textureMatrix = identity; matrixMode = mmProjection; + projMatrix = identity; for(auto &m : projStack) m = identity; + viewMatrix = identity; for(auto &m : viewStack) m = identity; + lightMatrix = identity; for(auto &m : lightStack) m = identity; + + for(auto &l : lights) { + l.enable = false; + l.color = Vector{0,0,0,0}; + l.direction = Vector{0,0,0,0}; + l.eyeVector = Vector{0,0,0,0}; + l.halfVector = Vector{0,0,0,0}; + } + diffuse = Vector{0,0,0,0}; + ambient = Vector{0,0,0,0}; + specular = Vector{0,0,0,0}; + emission = Vector{0,0,0,0}; + useShineTable = false; + for(auto &e : shininess) e = 0; + + normal = Vector{0,0,0,0}; + vertex.position = Vector{0,0,0,0x1000}; + vertex.texCoord = Vector{0,0,0,0x1000}; + vertex.color = Vector{0x3f000,0x3f000,0x3f000,0}; + + primitive.size = 0; + primitive.winding = 0; + primitive.type = PS::tris; + primitive.attributes = attributes = 0; + primitive.texImage = texImage = 0; + primitive.texPalette = texPalette = 0; + primitive.texTransform = PS::ttNone; + + // Render state + renderControl.texturing = false; + renderControl.toonShading = RC::darken; + renderControl.edgeMode = RC::solid; + renderControl.fogMode = 0; + renderControl.fogLevel = 0; + renderControl.alphaTest = false; + renderControl.alphaBlend = false; + renderControl.backImage = false; + + backColor[0] = 0; fogColor[0] = 0; + backColor[1] = 0; fogColor[1] = 0; + backColor[2] = 0; fogColor[2] = 0; + backAlpha = 0; fogAlpha = 0; + backId = 0; fogZ = 0; + backX = 0; + backY = 0; minAlpha = 0; + backZ = 0x7fff; + + for(auto &e : fogTable) e = 0; + for(auto &e : edgeTable) e = Vector{0,0,0,0}; + for(auto &e : toonTable[0]) e = Vector{0,0,0,0}; + for(auto &e : toonTable[1]) e = Vector{0,0,0,0}; + + for(unsigned n = 0; n < 2; n++) { + drawList[n].first = 0; + drawList[n].last = 0; + drawList[n].nextPrim = 0; + drawList[n].lastPrim = 0; + } +} + +void GPU::scanline() { + uint8 renderTime = (video.line + 50) % 263; + + if(renderTime < 241 && renderedLines < 192+1) { + // Rendering starts in advance. Draw time varies; however, up to 48 extra + // scanlines can be cached, providing a buffer for complicated scenes. + // + // That isn't emulated at the moment. Scanline rendering is still needed, + // however, to get stencilling and other edge cases right. + renderScanline(); + renderedLines++; + } + + if(renderTime == 242) { + // Finished rendering - process the new scene list. + // Games are free to load textures during this time. + swapBuffers(); + renderedLines = -1; + + drawList[0].nextPrim = 0; + drawList[0].lastPrim = renderList->firstAlpha; + drawList[0].first = 0; + drawList[0].last = 0; + + drawList[1].nextPrim = renderList->firstAlpha; + drawList[1].lastPrim = renderList->numPrims; + drawList[1].first = 0; + drawList[1].last = 0; + + for(auto &line : pixels) for(auto &p : line) { + p.a.a = p.b.a = 0; + p.a.id = p.b.id = 0xff; + p.az = p.bz = 0x7fffffff; + } + } + + if(commandBufIrq) + arm9.interrupt.flags |= CPUCore::irqGeomBuf; +} + +void GPU::swapBuffers() { + if(sceneFinished) { + std::swap(uploadList, renderList); + + // These settings apply to the NEW list, not the old one. + uploadList->alphaSort = !(swapArgument >> 0); + uploadList->depthUseW = swapArgument >> 1; + uploadList->numVerts = 0; + uploadList->numPrims = 0; + + // Release the ARM9 if it was blocking on a command.. + sceneFinished = false; + //texCache.reset(); + + // Terminate the current strip, if any. + if(renderList->numPrims < 2048 && primitive.type >= 2 + && primitive.size >= (primitive.type==PS::quadStrip? 4 : 3)) + renderList->numPrims++; + + while(renderList->numPrims) { + auto &p = renderList->prims[renderList->numPrims-1]; + + // Ensure the program submitted enough vertices.. + // Amusingly, this case not only crashes us, but the real GPU as well. + // Should issue a diagnostic here. + // + // This check also catches the case where vertex RAM fills up, + // leaving the last primitive unfinished. + if(p.numVerts < 3 || p.numVerts < 4 && (p.drawMode & Prim::quadStrip)) { + renderList->numPrims--; + } else { + break; + } + } + primitive.size = 0; + + // Sort the new list + auto count = renderList->numPrims; + auto &prims = renderList->prims; + auto &verts = renderList->verts; + + renderList->firstAlpha = 0; + + for(unsigned n = 0; n < count; n++) { + renderList->order[n] = n; + + // Is this per primitive or per polygon? + prims[n].minY = 255; + prims[n].maxY = 0; + + // Clip range is x/w, y/w := +/- 0x40000000 + for(unsigned k = 0; k < prims[n].numVerts; k++) { + int32 y = 192 - verts[prims[n].firstVert + k].y/0x400000; + + prims[n].minY = min(prims[n].minY, y); + prims[n].maxY = max(prims[n].maxY, y); + } + + // Special case for wireframe... only edge pixels are drawn. + if(prims[n].alpha == 0) { + prims[n].alpha = 31; + prims[n].wire = 1; + } + // Alpha is not the only thing that can send a primitive to the + // translucent pile. Using textures with the alpha channel does it too. + prims[n].blend = prims[n].alpha < 31 + || prims[n].texFormat == Prim::A3_I5 + || prims[n].texFormat == Prim::A5_I3; + + if(prims[n].blend == 0) + renderList->firstAlpha++; + } + + std::sort(renderList->order, renderList->order+count, [&](uint16 i0, uint16 i1) -> bool { + auto &p0 = prims[i0], &p1 = prims[i1]; + + if(p0.blend != p1.blend) { + return p0.blend < p1.blend; // separate solid + blend passes + } + if(p0.blend == false || renderList->alphaSort) { + // Sort polygons towards the top of the screen first. They prolly + // do this to save time and avoid searching the entire list. + if(p0.minY != p1.minY) return p0.minY < p1.minY; + if(p0.maxY != p1.maxY) return p0.maxY < p1.maxY; + } + return i0 < i1; // retain order in case of blending or ties + }); + } +} + + + +uint32 GPU::regRenderOptions() { + return renderControl.texturing<<0 | renderControl.toonShading<<1 + | renderControl.alphaTest<<2 | renderControl.alphaBlend<<3 + | renderControl.edgeMode<<4 | renderControl.fogMode<<6 + | renderControl.fogLevel<<8 | renderControl.backImage<<14; +} + +uint32 GPU::regRenderLoad() { + return 48-2; +} + +void GPU::regRenderOptions(uint32 data, uint32 mask) { + if(mask & 0x00ff) { + renderControl.texturing = data >> 0; + renderControl.toonShading = data >> 1; + renderControl.alphaTest = data >> 2; + renderControl.alphaBlend = data >> 3; + renderControl.edgeMode = data >> 4; + renderControl.fogMode = data >> 6; + } + if(mask & 0x7f00) { + renderControl.fogLevel = data >> 8; + renderControl.backImage = data >> 14; + } +} + +void GPU::regRenderMinAlpha(uint32 data, uint32 mask) { + minAlpha ^= (minAlpha ^ data) & mask; +} + +void GPU::regRenderClearColor(uint32 data, uint32 mask) { + if(mask & 0x00007fff) { + backColor[0] = data>> 0 & 31; + backColor[1] = data>> 5 & 31; + backColor[2] = data>>10 & 31; + backFog = data>>15 & 1; + + for(unsigned n = 0; n < 3; n++) + backColor[n] = 2*backColor[n] + (backColor[n] > 0); + } + if(mask & 0x001f0000) backAlpha = data>>16 & 31; + if(mask & 0x3f000000) backId = data>>24 & 63; +} + +void GPU::regRenderClearCoord(uint32 data, uint32 mask) { + if(mask & 0x00007fff) backZ = data>>0; + if(mask & 0x00ff0000) backX = data>>16; + if(mask & 0xff000000) backY = data>>24; +} + +void GPU::regRenderFogColor(uint32 data, uint32 mask) { + if(mask & 0x00007fff) { + fogColor[0] = data>> 0 & 31; + fogColor[1] = data>> 5 & 31; + fogColor[2] = data>>10 & 31; + for(unsigned n = 0; n < 3; n++) + fogColor[n] = 2*fogColor[n] + (fogColor[n] > 0); + } + if(mask & 0x001f0000) { + fogAlpha = data>>16 & 31; + } +} + +void GPU::regRenderFogCoord(uint32 data, uint32 mask) { + if(mask & 0x00007fff) fogZ = data; +} + +void GPU::regRenderFogTable(unsigned index, uint32 data, uint32 mask) { + if(mask & 0x000000ff) fogTable[4*index+0] = data >> 0 & 0x7f; + if(mask & 0x0000ff00) fogTable[4*index+1] = data >> 8 & 0x7f; + if(mask & 0x00ff0000) fogTable[4*index+2] = data >> 16 & 0x7f; + if(mask & 0xff000000) fogTable[4*index+3] = data >> 24 & 0x7f; + + fogTable[32] = fogTable[31]; // extra element for lerping +} + +void GPU::regRenderEdgeTable(unsigned index, uint32 data, uint32 mask) { + //uint6 r0 = 2*uint5(data>> 0), r1 = 2*uint5(data>>16); + //uint6 g0 = 2*uint5(data>> 5), g1 = 2*uint5(data>>21); + //uint6 b0 = 2*uint5(data>>10), b1 = 2*uint5(data>>26); + // + //if(r0) r0++; if(r1) r1++; + //if(g0) g0++; if(g1) g1++; + //if(b0) b0++; if(b1) b1++; + // + //auto *edge = &edgeTable[2*index]; + // + //if(mask & 0x0000ffff) edge[0] = b0<<12 | g0<<6 | r0<<0; + //if(mask & 0xffff0000) edge[1] = b1<<12 | g1<<6 | r1<<0; + if(mask & 0x0000ffff) unpackColor(edgeTable[2*index+0], data>>0); + if(mask & 0xffff0000) unpackColor(edgeTable[2*index+1], data>>16); +} + +void GPU::regRenderToonTable(unsigned index, uint32 data, uint32 mask) { + auto &d0 = toonTable[0][2*index+0]; + auto &d1 = toonTable[0][2*index+1]; + auto &l0 = toonTable[1][2*index+0]; + auto &l1 = toonTable[1][2*index+1]; + + if(mask & 0x0000ffff) unpackColor(d0, data>>0); + if(mask & 0xffff0000) unpackColor(d1, data>>16); + + // Generate entries for lighten mode + l0 = d0; l1 = d1; + l0[0] += 0x1000; l1[0] += 0x1000; + l0[1] += 0x1000; l1[1] += 0x1000; + l0[2] += 0x1000; l1[2] += 0x1000; +} + + + +void GPU::regGeomMaxPointDepth(uint32 data, uint32 mask) { + +} + +void GPU::regGeomStatus(uint32 data, uint32 mask) { + data &= mask; + if(data & 1<<15) { + stackOverflow = false; + projSP = 0; + viewSP = 0; + } + + if(mask & 0xff000000) { + commandBufIrq = data>>30; + if(commandBufIrq) + arm9.interrupt.flags |= CPUCore::irqGeomBuf; + } +} + +uint32 GPU::regGeomStatus() { + return boxResult<<1 | (viewSP % 32)<<8 | projSP<<13 | stackOverflow<<15 + | 1<<25 | 1<<26 | commandBufIrq<<30; +} + +uint32 GPU::regGeomLoad() { + return uploadList->numPrims<<0 | uploadList->numVerts<<16; +} + +uint32 GPU::regGeomPosition(unsigned index) { + return vertexResult[index]; +} + +uint32 GPU::regGeomNormal(unsigned index) { + return uint16(int12(normalResult[index/2 + 0]))<<0 + | uint16(int12(normalResult[index/2 + 1]))<<16; +} + +uint32 GPU::regClipMatrix(unsigned index) { + uint2 col = index / 4; + uint2 row = index % 4; + + return clipMatrix[4*row + col]; +} + +uint32 GPU::regLightMatrix(unsigned index) { + uint2 col = index / 3; + uint2 row = index % 3; + + return lightMatrix[4*row + col]; +} + + + +void GPU::sendGeomBuffered(uint32 data) { + // On real hardware commands are buffered, and filling up this buffer + // forces an indefinite waitstate until the buffer drains. A swapBuffers + // command sits around 'til vblank, thereby throttling the game at 60fps. + + // Since we don't emulate that yet, this is the closest thing. + while(sceneFinished) { + arm9.step(16); + if(arm7.clock < -255) + co_switch(arm7.thread); + } + // Command bytes are packed 4 to a word.. + if(packedCommands) args[numArgs++] = data; + else packedCommands = data; + + // Take the first one and try to run it. + // It succeeds when enough arguments are provided. + // + // It's important to run ALL possible commands here, since some of them + // don't consume any arguments and the next invocation would erroneously + // pass data to the wrong command. + while(packedCommands && geomCommand(packedCommands)) { + numArgs = 0; + packedCommands >>= 8; + } + if(commandBufIrq) + arm9.interrupt.flags |= CPUCore::irqGeomBuf; +} + +void GPU::sendGeomImmediate(uint8 command, uint32 data) { + while(sceneFinished) { + arm9.step(16); + if(arm7.clock < -255) + co_switch(arm7.thread); + } + args[numArgs++] = data; + if(geomCommand(command)) { + numArgs = 0; + } + if(commandBufIrq) + arm9.interrupt.flags |= CPUCore::irqGeomBuf; +} + +bool GPU::geomCommand(uint8 command) { + switch(command) { + case 0x10: return gxMatrixMode(); + case 0x11: return gxMatrixPush(); + case 0x12: return gxMatrixPop(); + case 0x13: return gxMatrixStore(); + case 0x14: return gxMatrixRestore(); + case 0x15: return gxMatrixLoadIdentity(); + case 0x16: return gxMatrixLoad4x4(); + case 0x17: return gxMatrixLoad4x3(); + case 0x18: return gxMatrixMult4x4(); + case 0x19: return gxMatrixMult4x3(); + case 0x1a: return gxMatrixRotate(); + case 0x1b: return gxMatrixScale(); + case 0x1c: return gxMatrixTranslate(); + + case 0x20: return gxColor(); + case 0x21: return gxNormal(); + case 0x22: return gxTexCoord(); + case 0x23: return gxVertex3i_16(); + case 0x24: return gxVertex3i_10(); + case 0x25: return gxVertex2i_XY(); + case 0x26: return gxVertex2i_XZ(); + case 0x27: return gxVertex2i_YZ(); + case 0x28: return gxVertex3i_Rel(); + case 0x29: return gxAttribute(); + case 0x2a: return gxTexImage(); + case 0x2b: return gxTexPalette(); + + case 0x30: return gxLightDiffuseAmbient(); + case 0x31: return gxLightSpecularEmission(); + case 0x32: return gxLightDirection(); + case 0x33: return gxLightColor(); + case 0x34: return gxLightShininess(); + + case 0x40: return gxBeginPrimitive(); + case 0x50: return gxSwapBuffers(); + case 0x60: return gxViewport(); + + case 0x70: return gxCullTest(); + case 0x71: return gxPositionTest(); + case 0x72: return gxDirectionTest(); + } + return true; +} + + +#include "math.cpp" +#include "commands.cpp" +#include "geometry.cpp" +#include "render.cpp" +#include "textures.cpp" + +} diff --git a/bsnes/nds/gpu/gpu.hpp b/bsnes/nds/gpu/gpu.hpp new file mode 100644 index 00000000..cdaa59f4 --- /dev/null +++ b/bsnes/nds/gpu/gpu.hpp @@ -0,0 +1,77 @@ + +struct GPU { + GPU(); + + void power(); + void scanline(); + void swapBuffers(); + + void sendGeomBuffered(uint32 data); + void sendGeomImmediate(uint8 command, uint32 data); + bool geomCommand(uint8 command); + + // Once the geometry submitted by the program gets through transform, + // lighting, culling, and clipping, we've built a SceneList with: + struct Vertex { + // A single point within a primitive. + int64 x, y, z; // normalized device coordinates (xyz/w => -1..+1) + int32 u, v; // texture coordinates (u/w, v/w) + int32 r, g, b; // color (r/w, g/w, b/w) + int32 w; // + }; + struct Prim { + // A strip of triangles or quads - or a single, clipped n-gon. + // AFAIK, none of these attributes can change between primitives. + uint16 firstVert, numVerts; + uint8 minY, maxY; + uint1 blend, wire; + uint8 drawMode; enum { shadeMask=0x03, normal=0, decal=1, toon=2, stencil=3, + poly=0, triStrip=0x04, quadStrip=0x08, + colorKey=0x10, zequal=0x20, zwrite=0x40, fog=0x80 }; + uint8 id, alpha; + uint8 texFormat; enum { untextured, A3_I5, I2,I4,I8, packed, A5_I3, A1_RGB15 }; + uint8 texBorder[2]; enum { clamp=0, repeat=1, clamp_=4, mirror=5 }; + uint8 texSize[2]; // 8 << texSize + + uint16 texPalette; + uint32 texImage; + }; + + struct SceneList { + unsigned numVerts; + unsigned numPrims; + unsigned firstAlpha; + + Vertex verts[6144]; + Prim prims[2048]; + uint16 order[2048]; // by solid first, top Y, bottom Y, then index + + uint1 alphaSort; // Sort transparent geometry by Y coordinate? + uint1 depthUseW; // Use Z or W for depth buffering? + }; + + uint1 powered; + uint2 swapArgument; + SceneList sceneList[2]; + SceneList *uploadList; + SceneList *renderList; + + bool sceneFinished; + uint2 commandBufIrq; + int32 renderedLines; + uint32 packedCommands; + uint32 args[32], numArgs; + + uint32 output[256*192]; // ARGB5666 + + struct Matrix; + struct Vector; + struct ClipSpaceVertex; + + #include "math.hpp" + #include "commands.hpp" + #include "geometry.hpp" + #include "render.hpp" +}; + +extern GPU gpu; diff --git a/bsnes/nds/gpu/math.cpp b/bsnes/nds/gpu/math.cpp new file mode 100644 index 00000000..c44d9629 --- /dev/null +++ b/bsnes/nds/gpu/math.cpp @@ -0,0 +1,143 @@ + +// Flips a 4x4 matrix along the diagonal: +// |a b c d| |a e i m| +// |e f g h| -> |b f j n| +// |i j k l| |c g k o| +// |m n o p| |d h l p| +void GPU::Matrix::transpose() { + auto &m = *this; + std::swap(m(0,1), m(1,0)); + std::swap(m(0,2), m(2,0)); + std::swap(m(0,3), m(3,0)); + std::swap(m(1,2), m(2,1)); + std::swap(m(1,3), m(3,1)); + std::swap(m(2,3), m(3,2)); +} + +// Product of two matrices: M := M * T. +void GPU::transform(Matrix& m, Matrix t) { + t.transpose(); + for(unsigned i = 0; i < 4; i++) + transform(t, m(i)); +} + +// Product of 4x4 matrix and 4D vector: v := T * v. +void GPU::transform(const Matrix& t, int32* v) { + int32 vector[] = { v[0], v[1], v[2], v[3] }; + for(unsigned i = 0; i < 4; i++) + v[i] = dot(t(i), vector); +} + +// Dot product of two 4D vectors: s := a . b. +int32 GPU::dot(const int32* a, const int32* b) { + return ( (int64) a[0] * b[0] + + (int64) a[1] * b[1] + + (int64) a[2] * b[2] + + (int64) a[3] * b[3] ) + / 0x1000; +} + +// Given a 4D homogenous coordinate, returns a mask telling whether +// it's out of bounds. One bit per side of the clipping volume. +unsigned GPU::outcode(const ClipSpaceVertex &v) { + const int32 &x = v.position[0], &y = v.position[1]; + const int32 &z = v.position[2], &w = v.position[3]; + + unsigned code = 0; + if(x < -w) code += 1; if(x > +w) code += 2; // left, right + if(y < -w) code += 4; if(y > +w) code += 8; // bottom, top + if(z < -w) code += 16; if(z > +w) code += 32; // near, far + return code; +} + +// Looks at three triangle vertices and returns a signed value: +// negative (back face), zero (edge on), or positive (front face). +// +// AKA sign of Z from the cross product (v1-v0) x (v2-v1) in screen coordinates: +// Z = (v1-v0).x (v2-v1).y - (v1-v0).y (v2-v1).x +int GPU::facing(const ClipSpaceVertex &v0, const ClipSpaceVertex &v1, const ClipSpaceVertex &v2) { + // These are in homogenous space, so.. that's more like: + // Z = a + b - c, where + // a = (v0.x v1.y - v0.y v1.x) / (v0.w v1.w) + // b = (v1.x v2.y - v1.y v2.x) / (v1.w v2.w) + // c = (v0.x v2.y - v0.y v2.x) / (v0.w v2.w) + // + // Since only the sign matters, + // S = (a+b-c <=> 0) = (a+b <=> c) + // + // and knowing w is positive within the clipping volume, + // p = v0.w v1.w v2.w + // a' = a*p, b' = b*p, c' = c*p + // + // that makes the divisions disappear. + // x y y x w + int64 a = ((int64) v0.position[0]*v1.position[1] - (int64) v0.position[1]*v1.position[0]) / 0x1000 * v2.position[3]; + int64 b = ((int64) v1.position[0]*v2.position[1] - (int64) v1.position[1]*v2.position[0]) / 0x1000 * v0.position[3]; + int64 c = ((int64) v0.position[0]*v2.position[1] - (int64) v0.position[1]*v2.position[0]) / 0x1000 * v1.position[3]; + + int64 r = a + b - c; + return r<0? -1 : r>0? +1 : 0; +} + +// a is inside the clipping plane +// b is outside, and will be clipped to the +// intersection between AB and the clip plane. +// axis controls which of X,Y,Z is tested. +// side affects the sign of the W comparand. +GPU::ClipSpaceVertex GPU::clipEdge(const ClipSpaceVertex &a, const ClipSpaceVertex &b, unsigned axis, int side) { + // Normally, to find the intersection we would attempt to find the fraction + // of the edge that remains unclipped: + // t = (1 - ax) / (bx - ax) + // + // The problem is that we haven't divided by W. We end up with this mess: + // t = (1 - ax/aw) / (bx/bw - ax/aw) + // + // Not very helpful. Besides which we still need W for perspective-correct + // texturing. + // + // In homogenous space, the clipping volume is defined by: + // -w < {x,y,z} < +w + // + // So we expect the clipped vertex c to have: + // cx = +/-cw ; cx,cy,cz depending on the plane + // + // And for each {x,y,z,w}: + // cx = ax + t*(bx - ax) + // + // Expanding both sides of the first equation: + // ax + t*(bx - ax) = aw + t*(bw - aw) + // t*(bx - ax) - t*(bw - aw) = aw - ax + // t = (aw - ax) / ((bx - ax) - (bw - aw)) + // + // We end up with these two equations: + // t = (+aw - ax) / ((+aw - ax) - (+bw - bx)) ; cx=+cw + // t = (-aw - ax) / ((-aw - ax) - (-bw - bx)) ; cx=-cw + // + // or more simply: + // t = (ax - +aw) / ((ax - +aw) - (bx - +bw)) ; cx=+cw + // t = (ax - -aw) / ((ax - -aw) - (bx - -bw)) ; cx=-cw + // + // t = (ax +/- aw) / ((ax +/- aw) - (bx +/- bw)) + // + // So clipping requires one division per edge that crosses a clipping plane. + // Quite pleasant, actually. + ClipSpaceVertex c; + int32 ax_aw = a.position[axis] - side*a.position[3]; + int32 bx_bw = b.position[axis] - side*b.position[3]; + + if(ax_aw - bx_bw) { + int64 t = 0x40000000ll * ax_aw / (ax_aw - bx_bw); + + // t should be between 0 and 1. Rather than being a linear function of X/Y/Z + // it also includes W. But at this point it's just an interpolation. + for(unsigned n = 0; n < 4; n++) { + c.position[n] = a.position[n] + int64(b.position[n] - a.position[n]) * t/0x40000000; + c.texCoord[n] = a.texCoord[n] + int64(b.texCoord[n] - a.texCoord[n]) * t/0x40000000; + c.color[n] = a.color[n] + int64(b.color[n] - a.color[n] ) * t/0x40000000; + } + // Ensure vertex is exactly on the clipping plane, + // so we don't try and clip it again. + c.position[axis] = side*c.position[3]; + } + return c; +} diff --git a/bsnes/nds/gpu/math.hpp b/bsnes/nds/gpu/math.hpp new file mode 100644 index 00000000..74298f7e --- /dev/null +++ b/bsnes/nds/gpu/math.hpp @@ -0,0 +1,53 @@ + + struct Vector { + int32 v[4]; + + Vector() { } + + Vector(const std::initializer_list& elems) { + unsigned n = 0; + for(auto i : elems) { + if(n == 4) break; + v[n++] = i; + } + } + inline int32& operator[](unsigned i) { return v[i]; } + inline const int32& operator[](unsigned i) const { return v[i]; } + inline operator int32*() { return v; } + }; + + struct Matrix { + int32 m[4*4]; + + Matrix() { } + + Matrix(const std::initializer_list& elems) { + unsigned n = 0; + for(auto i: elems) + if(n < 4*4) m[n++] = i; + } + + inline int32& operator[](unsigned i) { return m[i]; } + inline int32& operator()(unsigned i, unsigned j) { return m[4*i + j]; } + inline int32* operator()(unsigned i) { return &m[4*i]; } + + inline const int32& operator[](unsigned i) const { return m[i]; } + inline const int32& operator()(unsigned i, unsigned j) const { return m[4*i + j]; } + inline const int32* operator()(unsigned i) const { return &m[4*i]; } + + void transpose(); + }; + + struct ClipSpaceVertex { + Vector position; + Vector texCoord; + Vector color; + }; + + static void transform(Matrix& m, Matrix t); + static void transform(const Matrix& t, int32* v); + + static int32 dot(const int32* a, const int32* b); + static int facing(const ClipSpaceVertex &v0, const ClipSpaceVertex &v1, const ClipSpaceVertex &v2); + static unsigned outcode(const ClipSpaceVertex &v); + static ClipSpaceVertex clipEdge(const ClipSpaceVertex &b, const ClipSpaceVertex &a, unsigned axis, int side); diff --git a/bsnes/nds/gpu/render.cpp b/bsnes/nds/gpu/render.cpp new file mode 100644 index 00000000..8439329e --- /dev/null +++ b/bsnes/nds/gpu/render.cpp @@ -0,0 +1,578 @@ + +void GPU::updateDrawList(int y, DrawList& list, bool sorted) { + // Blah, why are polys with numVerts==0 making it in? + + // Remove polygons that have finished rendering + while(list.first < list.last && (!list.polys[list.first].numVerts + || 192-list.polys[list.first].v[list.polys[list.first].numVerts-1]->y/0x400000 < y)) + list.first++; + + // Add primitives matching Y as their first line + unsigned pi = list.nextPrim; + while(pi < list.lastPrim) { + auto *prim = &renderList->prims[renderList->order[pi]]; + if(sorted && y < prim->minY-1) + break; + + if(!sorted || y == prim->minY-1) { + auto *v = &renderList->verts[prim->firstVert]; + + if(prim->drawMode & Prim::triStrip) { + for(unsigned n = 2; n < prim->numVerts; n += 1, v += 1) + setupPoly(list.polys[list.last++], prim, v, 3); + } + else if(prim->drawMode & Prim::quadStrip) { + for(unsigned n = 2; n < prim->numVerts; n += 2, v += 2) + setupPoly(list.polys[list.last++], prim, v, 4); + } + else { + setupPoly(list.polys[list.last++], prim, v, prim->numVerts); + } + + if(list.nextPrim == pi) + list.nextPrim++; + } + pi++; + } +} + +void GPU::setupPoly(ActivePoly& poly, Prim* prim, Vertex *vs, unsigned numVerts) { + for(unsigned n = 0; n < numVerts; n++) + poly.v[n] = &vs[n]; + + // Sort vertices by Y, then X if on same line + std::sort(poly.v, poly.v+numVerts, [](Vertex *a, Vertex *b) + { return a->y != b->y? a->y > b->y : a->x < b->x; }); + + poly.numVerts = numVerts; + if(!numVerts) return; + + poly.p = prim; + poly.lv = poly.next_lv = 0; // start at top vertex + poly.rv = poly.next_rv = 0; + poly.side[0] = 0; // top and bottom are + poly.side[numVerts-1] = 0; // considered to be on both sides. + + // Find out which side each vertex is on. This is based on the observation + // that with a convex polygon, edges always curve inwards, towards the other + // side. So we switch sides every time the curve changes direction. + for(int n = 1; n < numVerts-1; n++) { + int64 dx0 = poly.v[n]->x - poly.v[n-1]->x; + int64 dx1 = poly.v[n+1]->x - poly.v[n]->x; + int64 dy0 = -(poly.v[n]->y - poly.v[n-1]->y); + int64 dy1 = -(poly.v[n+1]->y - poly.v[n]->y); + + poly.side[n] = poly.side[n-1]; // special case for straight or co-linear edges + + if(!dy0) dy0 = 1; + if(!dy1) dy1 = 1; + + // compare dx1/dy1 <=> dx0/dy0 + // - both sides have been multiplied by dy0*dy1 to avoid division by 0 + if(dx1*dy0 > dx0*dy1) poly.side[n] = -1; // curves to the right, so must be on the left + if(dx1*dy0 < dx0*dy1) poly.side[n] = +1; // curves to the left, so must be on the right + } + setupNextEdge(poly, poly.lv, poly.next_lv, -1, poly.lnext, poly.dl_dv); + setupNextEdge(poly, poly.rv, poly.next_rv, +1, poly.rnext, poly.dr_dv); + + poly.prev_lx = poly.lnext.x; + poly.prev_rx = poly.rnext.x; +} + +void GPU::setupNextEdge(ActivePoly& poly, unsigned& vi, unsigned& next, + int side, Interpolants& edge, Interpolants& gradient) +{ + vi = next++; + while(poly.side[next]*side < 0) + next++; + + Interpolants endpoint; + assignEdge(edge, poly.v[vi]); edge.x &= ~0x3fffff; + assignEdge(endpoint, poly.v[next]); endpoint.x &= ~0x3fffff; + + int32 y0 = 192 - poly.v[vi]->y/0x400000; + int32 y1 = 192 - poly.v[next]->y/0x400000; + int32 numLines = y1 - y0; + if(numLines) { + for(unsigned j = 0; j < Interpolants::count; j++) + gradient[j] = (endpoint[j] - edge[j]) / numLines; + } +} + +void GPU::assignEdge(Interpolants& edge, Vertex* v) { + edge.r = v->r; edge.u = v->u; + edge.g = v->g; edge.v = v->v; + edge.b = v->b; edge.z = v->z; + + edge.inv_w = 0x80000000000/max(1,v->w); + edge.x = v->x; +} + + + +void GPU::renderScanline() { + int y = renderedLines; + auto *line = 1 + pixels[y-0 & 3]; + auto *line1 = 1 + pixels[y-1 & 3]; + auto *line2 = 1 + pixels[y-2 & 3]; + + updateDrawList(y, drawList[0], true); + updateDrawList(y, drawList[1], renderList->alphaSort); + + unsigned backOffs = 0x40000 + 512*(backY+y & 0xff); + uint16 *backImageColor = &system.vmap.tex[backOffs+0x00000 >> 14][backOffs+0x00000]; + uint16 *backImageDepth = &system.vmap.tex[backOffs+0x20000 >> 14][backOffs+0x20000]; + + for(int x = -1; x <= 256; x++) { + auto &px = line[x]; + uint16 color = backImageColor[backX+x & 0xff]; + uint16 depth = backImageDepth[backX+x & 0xff]; + + // Stencil is preserved, even between frames! + // Transitioning to stencilMode=1 is what clears it. + px.flags &= Pixel::stencil; + px.flags &= ~Pixel::blends; + + if(renderControl.backImage) { + px.a.r = color<<1 & 62; px.a.r += px.a.r > 0; + px.a.g = color>>4 & 62; px.a.g += px.a.g > 0; + px.a.b = color>>9 & 62; px.a.b += px.a.b > 0; + px.a.a = color>>15? 31 : 0; + px.a.id = backId; + px.az = depth<<16 & 0x7fff0000; + + if(depth & 1<<15) px.flags |= Pixel::fog; + } + else { + px.a.r = backColor[0]; + px.a.g = backColor[1]; + px.a.b = backColor[2]; + px.a.a = backAlpha; + px.a.id = backId; + px.az = backZ<<16; + + if(backFog) px.flags |= Pixel::fog; + } + + px.b.a = 0; + px.b.id = 0xff; + px.bz = 0x7fffffff; + px.sz = 0x7fffffff; + } + + renderDrawList(y, drawList[0], false); + renderDrawList(y, drawList[1], true); + if(y < 1) return; + + y--; // edge filter requires 1 line latency + + int32 fogZ = this->fogZ << 16; + uint32 *__restrict dest = &output[256*y]; + + for(int x = 0; x < 256; x++) { + // Any remaining fragments are combined here... or maybe this should + // be done between solid/alpha passes? I'm not sure if you can get a + // transparent pixel between a solid and a smooth edge, and still have + // it look right. + auto &px = line1[x]; + auto &above = px.a; + auto &below = px.b; + uint8 r = above.r; + uint8 g = above.g; + uint8 b = above.b; + uint8 a = above.a; + uint8 id = above.id; + int64 z = px.az; + + if(px.flags & Pixel::edge) { + auto &up = line2[x]; + auto &left = line1[x-1], &right = line1[x+1]; + auto &down = line[x]; + + // Toon edge filter - need to verify logic here, might be &&, etc. + if( z < up.az && id != up.a.id || z < down.az && id != down.a.id + || z < left.az && id != left.a.id || z < right.az && id != right.a.id + ) { + Vector outline = edgeTable[id/8]; + + if(renderControl.edgeMode & RC::toon) { + // Replace RGB with values from the table. + // Is there an option to disable this for some polygons? + r = outline[0] / 0x1000; + g = outline[1] / 0x1000; + b = outline[2] / 0x1000; + + // In this case, alpha is also overwritten. Edges that don't + // pass the filter remain antialiased, as in "smooth" mode. + if(renderControl.edgeMode == RC::blended) + a = 16; // fixed value - or is there a register? + } + } + } + + if(below.a /*not empty*/) { + if(below.id == id && a < 31 && (px.flags & Pixel::blends)) { + // Don't blend equal object IDs + r = below.r; + g = below.g; + b = below.b; + a = below.a; + } + else if(renderControl.alphaBlend || !(px.flags & Pixel::blends)) { + // Z blends, too! You can see this if you set fogAlpha=0 + // with edge smoothing on. + z = px.bz + (z - px.bz) * (a+1) / 32u; + + // They cheaped out here. To get correct Photoshop-style alpha + // (non pre-multiplied) requires dividing by A. It's nasty. + r = below.r + (r - below.r) * (a+1) / 32u; + g = below.g + (g - below.g) * (a+1) / 32u; + b = below.b + (b - below.b) * (a+1) / 32u; + a = max(a, below.a); + } + } + + // Polygons can be fogged toward a constant RGBA, or optionally just + // their alpha channel. Unlike most systems, this is a per-pixel effect + // based on the Z buffer. + if(px.flags & Pixel::fog) { + // Z := 0..0x7fffffff + int32 dist = z-fogZ >> 16-renderControl.fogLevel; + dist = max(0, min(0x7fff, dist)); + + int32 ifog = fogTable[dist/0x400u]; + ifog += (fogTable[dist/0x400u + 1] - ifog) * (dist & 0x3ff)/0x400u; + + if(renderControl.fogMode == RC::color) { + r += (fogColor[0] - r) * (ifog+1)/0x80u; + g += (fogColor[1] - g) * (ifog+1)/0x80u; + b += (fogColor[2] - b) * (ifog+1)/0x80u; + } + a += (fogAlpha - a) * (ifog+1)/0x80u; + } + *dest++ = a<<18 | b<<12 | g<<6 | r<<0; + } +} + +void GPU::renderDrawList(int y, DrawList& list, bool blend) { + auto *line = 1 + pixels[y & 3]; + + unsigned alphaTest = minAlpha * renderControl.alphaTest; + + for(unsigned n = list.first; n < list.last; n++) { + auto &poly = list.polys[n]; + if(!poly.numVerts) continue; + + int y0 = 192-poly.v[0]->y/0x400000; + int y1 = 192-poly.v[poly.numVerts-1]->y/0x400000; + + if(y < y0-1 || y >= y1) continue; + + while(y == 192-poly.v[poly.next_lv]->y/0x400000-1 && poly.next_lv < poly.numVerts-1) + setupNextEdge(poly, poly.lv, poly.next_lv, -1, poly.lnext, poly.dl_dv); + + while(y == 192-poly.v[poly.next_rv]->y/0x400000-1 && poly.next_rv < poly.numVerts-1) + setupNextEdge(poly, poly.rv, poly.next_rv, +1, poly.rnext, poly.dr_dv); + + // X range for previous, current, and next line + // We need this to determine "edge" cases (sorry) -> + int px0 = poly.prev_lx / 0x400000; // Top: x in x0..prev_x0 + int px1 = poly.prev_rx / 0x400000; // or prev_x1..x1 + int x0 = poly.left.x / 0x400000; // Bottom: x in x0..next_x0 + int x1 = poly.right.x / 0x400000; // or next_x1..x1 + int nx0 = poly.lnext.x / 0x400000; // Left: x+0 == x0 + int nx1 = poly.rnext.x / 0x400000; // Right: x+1 == x1 + + // Theory: + // A pixel is marked "edge" on one of the above conditions. Translucent + // (alpha < 31) polygons do not modify the edge flags. Smooth edges have + // their alpha set to the fraction of pixel covered. + + // Test for dropout - DS doesn't have explicit line or point primitives; + // to draw them, you simply use geometry thinner than 1px. The rasterizer + // ALMOST never leaves holes.. even in extremely narrow triangles. Very + // occasionally, degenerate triangles will have gaps. + if(x0 > px1) x0 = px1; + if(x1 < px0) x1 = px0; + if(x1 <= x0) x1 = x0; + + if(y >= y0) { + Texture *tex = nullptr; + if(renderControl.texturing) + tex = getTexture(poly.p->texImage, poly.p->texPalette); + + Interpolants i = poly.left; // RGB, UVZW at current pixel + Interpolants delta; // Gradient from left to right edges + + if(x1 > x0) + for(unsigned j = 0; j < Interpolants::count; j++) + delta[j] = (poly.left[j] - poly.right[j]) / (x0-x1); + + uint8 id = poly.p->id; + int drawMode = poly.p->drawMode; + int shadeMode = drawMode & Prim::shadeMask; + + if(!renderControl.fogMode) + drawMode &= ~Prim::fog; + + if((drawMode & Prim::shadeMask) == Prim::stencil) { + if(id) { + stencilMode = false; // Draw to screen, using stencil bits as mask. + } + else if(stencilMode == false) { + stencilMode = true; // Draw to stencil buffer. + + // Toggling into stencil mode with ID=0 was observed to clear the + // stencil buffer. This IS affected by polygon sorting so it will + // not happen on every line, or even every frame, unless so arranged! + // + // The buffer holds data for only 2 lines, and if not cleared, then + // old data is used. So shadow volumes must be closed to work. + for(unsigned x = 0; x < 256; x++) + line[x].flags &= ~Pixel::stencil; + } + } + + if(i.inv_w < 0x2000) i.inv_w = 0x2000; + + // Hrm. Too many variables here, this should be split up. Perhaps: + // pass 1: calculate edge coverage (a==31 only) + // pass 2: if z <= bz, calculate [argbf]z (modulate, decal, toon, stencil) + // pass 3: do atest, ztest (less, equal), merge with line buffer (a==31, a<31)? + + for(unsigned x = x0; x <= x1; x++) { + int32 w = 0x80000000000ll / max(2ll, i.inv_w); + int32 z = i.z + 0x40000000; // z/w + + // Should find some way to justify this - <<7 was Selected for + // suitable fog in Mario Kart's Chocolate Mountain course.. + if(renderList->depthUseW) + z = w<<7; + + // Unproject the interpolated values + int32 u = ((int64) i.u * w)/0x40000000; + int32 v = ((int64) i.v * w)/0x40000000; + + Vector color = { + min(63, (int64) i.r * w/0x4000000), + min(63, (int64) i.g * w/0x4000000), + min(63, (int64) i.b * w/0x4000000), + poly.p->alpha + }; + + i.u += delta.u; i.r += delta.r; + i.v += delta.v; i.g += delta.g; + i.z += delta.z; i.b += delta.b; + i.inv_w += delta.inv_w; + + bool edge = false; + + if(blend == false) { + edge = x0 <= x && (x <= px0 || x <= nx0) + || (px1 <= x || nx1 <= x) && x <= x1 + || x == x0 || x == x1; + + if(renderControl.edgeMode & RC::smooth) { + if(x == x0) color[3] = 31-(poly.left.x>>17 & 31); + if(x == x1) color[3] = (poly.right.x>>17 & 31); + } + } + + Vector texColor = { 63, 63, 63, 31 }; + if(tex) { + u = max(0, min(tex->width-1, u & tex->umask)); + v = max(0, min(tex->height-1, v & tex->vmask)); + + uint32 abgr = tex->image[tex->width*v + u]; + texColor[0] = 2*(abgr>> 0 & 31) + 1; + texColor[1] = 2*(abgr>> 5 & 31) + 1; + texColor[2] = 2*(abgr>>10 & 31) + 1; + texColor[3] = (abgr>>15); + } + + auto &px = line[x]; + auto &above = px.a; + auto &below = px.b; + bool ztest_a = drawMode & Prim::zequal? z == px.az : z < px.az; + bool ztest_b = drawMode & Prim::zequal? z == px.bz : z < px.bz; + + if(shadeMode == Prim::stencil) { + if(stencilMode) { + // Draw to stencil buffer, not the screen + // Does texturing work here? Alpha, maybe? + if(ztest_a == false) { + px.flags |= Pixel::stencil; + px.sz = px.az; + } + continue; + } + // Mask polygons using the stencil buffer + if(px.flags & Pixel::stencil) { + // Succeeded - force Z onto the fragment being shadowed + z = px.sz; + if(id == above.id) { + // FF IV surrounds characters in shadow volumes, and uses the ID + // to prevent self-shadowing. So technically this fragment is on + // top, yet the DS somehow draws it underneath the model. If not + // done this way, edge smoothing would clash with the shadow. + ztest_a = false; + ztest_b = true; + z = px.bz; + } + } else { + // Failed stencil test + continue; + } + } + + if(shadeMode == Prim::toon) { + // Look up shade based on the red channel + int a = color[3]; + color = toonTable[renderControl.toonShading][color[0]/2 & 31]; + color[0] /= 0x1000u; + color[1] /= 0x1000u; + color[2] /= 0x1000u; + color[3] = a; + } + + if(shadeMode == Prim::decal) { + color[0] += (texColor[0] - color[0]) * (texColor[3]+1) / 32u; + color[1] += (texColor[1] - color[1]) * (texColor[3]+1) / 32u; + color[2] += (texColor[2] - color[2]) * (texColor[3]+1) / 32u; + } else { + color[0] = color[0] * texColor[0] / 64u; + color[1] = color[1] * texColor[1] / 64u; + color[2] = color[2] * texColor[2] / 64u; + color[3] = (1 + color[3]) * texColor[3] / 32u; + } + + if(color[3] <= renderControl.alphaTest) + continue; + + if(blend) { + if(ztest_a) { + if(above.id == id) continue; + + if(!renderControl.alphaBlend) { + // Mario Kart uses this on the car selection screen. The alpha + // and coverage are still retained and used for PPU blending. + above.r = color[0]; + above.g = color[1]; + above.b = color[2]; + above.a = max(color[3], px.a.a); + above.id = id; + + if(!(drawMode & Prim::fog)) px.flags &= ~Pixel::fog; + if(drawMode & Prim::zwrite) px.az = z; + continue; + } + + if(below.a /*not empty*/) { + if(below.id != above.id || color[3] == 31 || !(px.flags & Pixel::blends)) { + // Merge the top pixel down to make room + px.bz += int64(px.az - px.bz) * (above.a + 1)/32u; + + below.r += (above.r - below.r) * (above.a + 1)/32u; + below.g += (above.g - below.g) * (above.a + 1)/32u; + below.b += (above.b - below.b) * (above.a + 1)/32u; + below.a = max(above.a, below.a); + below.id = above.id; + } + } else { + // Bottom empty or top solid, simply push down + below = above; + px.bz = px.az; + } + // Then write the top one + above.r = color[0]; + above.g = color[1]; + above.b = color[2]; + above.a = color[3]; + above.id = id; + + // AND with previous fog bit + if(!(drawMode & Prim::fog)) px.flags &= ~Pixel::fog; + if(drawMode & Prim::zwrite) px.az = z; + + px.flags |= Pixel::blends; + } + else if(ztest_b) { + if(below.a /*not empty*/) { + if(below.id == id && color[3] < 31) continue; + + if(!renderControl.alphaBlend) { + if(drawMode & Prim::zwrite) + px.bz = z; + + below.r = color[0]; + below.g = color[1]; + below.b = color[2]; + } + else { + // Blend into bottom pixel + if(drawMode & Prim::zwrite) + px.bz += int64(z - px.bz) * (color[3] + 1)/32u; + + below.r += (color[0] - below.r) * (color[3] + 1)/32u; + below.g += (color[1] - below.g) * (color[3] + 1)/32u; + below.b += (color[2] - below.b) * (color[3] + 1)/32u; + } + below.a = max(color[3], below.a); + below.id = id; + } else { + // Bottom empty, simply replace + if(drawMode & Prim::zwrite) + px.bz = z; + + below.r = color[0]; + below.g = color[1]; + below.b = color[2]; + below.a = color[3]; + below.id = id; + } + } + continue; + } + + if(ztest_a) { + if(drawMode & Prim::fog) px.flags |= Pixel::fog; + else px.flags &= ~Pixel::fog; + + // Push the top pixel down. Anything beneath is lost. + // Check first to avoid breaking backAlpha == 0. + if(above.a /*not empty*/) { + px.bz = px.az; + below = above; + below.a = 31; + } + above.r = color[0]; + above.g = color[1]; + above.b = color[2]; + above.a = color[3]; + above.id = id; + px.az = z; + + if(edge) px.flags |= Pixel::edge; + else px.flags &= ~Pixel::edge; + } + else if(ztest_b) { + below.r = color[0]; + below.g = color[1]; + below.b = color[2]; + below.a = 31; + below.id = id; + px.bz = z; + } + } + poly.prev_lx = poly.left.x; + poly.prev_rx = poly.right.x; + } + poly.left = poly.lnext; + poly.right = poly.rnext; + + for(unsigned j = 0; j < Interpolants::count; j++) { + poly.lnext[j] += poly.dl_dv[j]; + poly.rnext[j] += poly.dr_dv[j]; + } + } +} diff --git a/bsnes/nds/gpu/render.hpp b/bsnes/nds/gpu/render.hpp new file mode 100644 index 00000000..77e56562 --- /dev/null +++ b/bsnes/nds/gpu/render.hpp @@ -0,0 +1,163 @@ + + struct ActivePoly; + union Interpolants; + struct DrawList; + + void updateDrawList(int y, DrawList& list, bool sorted); + void setupPoly(ActivePoly& poly, Prim* prim, Vertex *vs, unsigned numVerts); + void setupNextEdge(ActivePoly& poly, unsigned& vi, unsigned& next, int side, Interpolants& edge, Interpolants& gradient); + void assignEdge(Interpolants& edge, Vertex* v); + + void renderScanline(); + void renderDrawList(int y, DrawList& list, bool blend); + + uint32 regRenderOptions(); + uint32 regRenderLoad(); + + void regRenderOptions(uint32 data, uint32 mask); + void regRenderMinAlpha(uint32 data, uint32 mask); + void regRenderClearColor(uint32 data, uint32 mask); + void regRenderClearCoord(uint32 data, uint32 mask); + void regRenderFogColor(uint32 data, uint32 mask); + void regRenderFogCoord(uint32 data, uint32 mask); + void regRenderFogTable(unsigned index, uint32 data, uint32 mask); + void regRenderEdgeTable(unsigned index, uint32 data, uint32 mask); + void regRenderToonTable(unsigned index, uint32 data, uint32 mask); + + struct Texture { + // Lookup data - 44 significant bits + uint64 key; // paladdr<<32 | format<<16 | texaddr<<0 + uint32 imageBase, indexBase, colorBase; + + // Mirrored textures: clamp at 2*size, wrap at 2*size, cache all 4 mirrors + // Repeating textures: clamp dt 1*size, wrap at 1*size + // Clamped textures: clamp at 1*size, wrap at UINT_MAX + int32 width, height; + int32 umask, vmask; + uint32 *image; + + // Address ranges for dirty checks + uint32 texelRange[2]; // pixel data + uint32 indexRange[2]; // for compressed format + uint32 colorRange[2]; // for paletted formats + + ~Texture() { delete[] image; } + Texture(uint64 key, int width, int height) : key(key), + width(width), height(height), umask(~0), vmask(~0), image(nullptr) {} + }; + + struct TexCache { + void reset(); + void flushDirty(unsigned bank); + bool checkDirty(Texture *texture, uint32 *range, VRAMMapping *map, uint32 mask); + + void add(Texture *t); + Texture *get(uint64 key); + + enum { tableSize = 1<<10 }; + vector table[tableSize]; + int size; + } texCache; + + Texture *getTexture(uint32 texImage, uint16 texPalette); + void mirrorTexture(Texture *tex, int width, int height); + void convertPacked(Texture *tex, int width, int height); + void convertI2(Texture *tex, int width, int height, bool colorKey); + void convertI3(Texture *tex, int width, int height); + void convertI4(Texture *tex, int width, int height, bool colorKey); + void convertI5(Texture *tex, int width, int height); + void convertI8(Texture *tex, int width, int height, bool colorKey); + void convertARGB(Texture *tex, int width, int height); + + + union Interpolants { + int64& operator[](unsigned i) { return val[i]; } + + int64 val[8]; enum { count=8 }; + struct { + int64 r, g, b, u, v, z, inv_w, x; + }; + }; + + struct ActivePoly { + Prim *p; + uint8 numVerts; + int8 side[8]; // is vertex on left or right? + Vertex *v[8]; + Interpolants left, right; // current values at l, r + Interpolants lnext, rnext; + Interpolants dl_dv, dr_dv; // gradient down each side + unsigned lv, rv; // index of current vertex + unsigned next_lv, next_rv; // index of next vertex + int32 prev_lx, prev_rx; // x span on previous line + }; + + struct Pixel { + // Z for depth sorting. We need two layers (!) to make edge smoothing + // independent of draw order. It also saves the trouble of blending every + // pixel drawn - the worst case is a single pass at the end. + int32 az, bz; // at least 24 bits? 15 bit had too much Z fighting :/ + int32 sz; // shadow buffer z + struct { + uint8 r, g, b; // 6 bits + uint8 a; // 5 bits + + // Object ID is a kludge Nintendo came up with to deal with edge fill. + // They chose to make all polygon edges overlap, so their antialiasing + // looks right. However, this means translucent edge pixels would be + // drawn twice. The object ID is used to suppress that. + uint8 id; + } a, b; + + // Some miscellaneous bits, only one layer here. + // There have been comments to the effect that multiple stencil bits are + // needed, but I don't think that's true - shadow volumes are drawn one + // at a time with the stencil cleared in-between, and the object ID + // prevents shadows blending more than once per pixel per light. + uint8 flags; enum { + fog = 1<<7, // apply post pass Z-based fogging + edge = 1<<6, // apply post pass toon edge filter + stencil = 1<<5, // pixels can be drawn here in stencil mode + blends = 1<<4, // if true, treat a as alpha; else as coverage + }; + }; + + struct RC { + uint1 texturing; + uint1 toonShading; enum { darken, lighten }; + uint2 edgeMode; enum { solid, smooth, toon, blended }; + uint2 fogMode; enum { color=2, alpha=3 }; + uint4 fogLevel; + uint1 alphaTest; + uint1 alphaBlend; + uint1 backImage; + } renderControl; + + struct DrawList { + unsigned first, last; + unsigned nextPrim, lastPrim; + ActivePoly polys[6144]; + } drawList[2]; // 2 passes - solid and translucent + + uint5 minAlpha; + + uint6 backColor[3]; + uint5 backAlpha; + uint6 backId; + uint8 backX, backY; + uint15 backZ; + uint1 backFog; + + int8 fogTable[32+1]; + uint6 fogColor[3]; + uint5 fogAlpha; + int16 fogZ; + + bool stencilMode; + + Vector toonTable[2][32]; + Vector edgeTable[8]; + + // Need two buffers here for edge transparency + // Need three for toon edges, argh. Will redo later. + Pixel pixels[4][256+2]; diff --git a/bsnes/nds/gpu/textures.cpp b/bsnes/nds/gpu/textures.cpp new file mode 100644 index 00000000..c3bbbfea --- /dev/null +++ b/bsnes/nds/gpu/textures.cpp @@ -0,0 +1,304 @@ + +void GPU::TexCache::reset() { + for(auto &bucket : table) { + for(auto &texture : bucket) + delete texture; + + bucket.reset(); + } + size = 0; +} + +bool GPU::TexCache::checkDirty(Texture *texture, uint32 *range, VRAMMapping* map, uint32 mask) { + uint32 addr = range[0] & ~255 & mask; + uint32 end = range[1] + 255 & ~255 & mask; + + for(; addr != end; addr = addr+256 & mask) + if(map[addr>>14].dirty(addr)) return true; + + return false; +} + +void GPU::TexCache::flushDirty(unsigned bank) { + // Called whenever VRAM is (re-)assigned as texture memory + // (ie. the game finished uploading and has locked it). + bool palMem = bank >= 4; + + for(auto &bucket : table) { + for(auto &texture : bucket) { + if(!(!palMem && checkDirty(texture, texture->texelRange, system.vmap.tex, 0x7ffff) + || !palMem && checkDirty(texture, texture->indexRange, system.vmap.tex, 0x7ffff) + || palMem && checkDirty(texture, texture->colorRange, system.vmap.texpal, 0x1ffff) )) + continue; + + delete texture; + texture = nullptr; + } + // Flush all the nullptrs at once to avoid O(n^2) removal. + unsigned count = 0; + for(unsigned n = 0; n < bucket.size(); n++) { + if(bucket[n]) bucket[count++] = bucket[n]; + } + bucket.resize(count); + } +} + + +void GPU::TexCache::add(Texture *t) { + uint10 hash = t->key ^ t->key>>10 ^ t->key>>20 ^ t->key>>30; + table[hash].append(t); + size++; +} + +GPU::Texture* GPU::TexCache::get(uint64 key) { + uint10 hash = key ^ key>>10 ^ key>>20 ^ key>>30; + + for(auto texture : table[hash]) { + if(texture->key == key) + return texture; + } + return nullptr; +} + + + +GPU::Texture *GPU::getTexture(uint32 texImage, uint16 texPalette) { + //texCache.reset(); + + uint64 key = (uint64) texImage ^ (uint64)texPalette<<30; + Texture *tex = texCache.get(key); + + if(!tex) { + int format = texImage>>26 & 7; + if(!format) return nullptr; + + bool colorKey = texImage & 1<<29; + unsigned uaxis = texImage>>16 & 5; + unsigned vaxis = texImage>>17 & 5; + unsigned imgwidth = 8 << (texImage>>20 & 7); + unsigned imgheight = 8 << (texImage>>23 & 7); + + tex = new Texture(key, imgwidth, imgheight); + + tex->colorBase = 8*(texPalette & 0x3fff); + tex->imageBase = 8*(texImage & 0xffff); + tex->indexBase = 0x20000 + (tex->imageBase/2 & 0xffff); + if(tex->imageBase >= 0x40000) + tex->indexBase += 0x10000; + + // Mirroring implies repeat as well. + if(uaxis == Prim::mirror) tex->width *= 2; + if(vaxis == Prim::mirror) tex->height *= 2; + if(uaxis & Prim::repeat) tex->umask = tex->width-1; + if(vaxis & Prim::repeat) tex->vmask = tex->height-1; + + tex->image = new uint32[tex->width * tex->height]; + tex->colorRange[0] = tex->colorRange[1] = tex->colorBase; + tex->texelRange[0] = tex->texelRange[1] = tex->imageBase; + tex->indexRange[0] = tex->indexRange[1] = tex->indexBase; + + switch(format) { + case Prim::packed: convertPacked(tex, imgwidth, imgheight); break; + case Prim::I2: convertI2(tex, imgwidth, imgheight, colorKey); break; + case Prim::A5_I3: convertI3(tex, imgwidth, imgheight); break; + case Prim::I4: convertI4(tex, imgwidth, imgheight, colorKey); break; + case Prim::A3_I5: convertI5(tex, imgwidth, imgheight); break; + case Prim::I8: convertI8(tex, imgwidth, imgheight, colorKey); break; + case Prim::A1_RGB15: convertARGB(tex, imgwidth, imgheight); break; + } + mirrorTexture(tex, imgwidth, imgheight); + texCache.add(tex); + } + return tex; +} + +void GPU::mirrorTexture(Texture *tex, int width, int height) { + for(int y = 0; y < height; y++) { + uint32 *row = &tex->image[tex->width*y]; + uint32 *mirror = &tex->image[tex->width*(tex->height-1 - y)]; + + if(tex->width > width) { + for(int x = 0; x < width; x++) + row[tex->width-1 - x] = row[x]; + } + if(tex->height > height) { + memcpy(mirror, row, tex->width*sizeof(*row)); + } + } +} + +void GPU::convertPacked(Texture *tex, int width, int height) { + uint32 taddr = tex->imageBase; + uint32 caddr = tex->indexBase; + + tex->texelRange[1] += (width/4)*(height/4)*4; + tex->indexRange[1] += (width/4)*(height/4)*2; + tex->colorRange[0] += 0x10000; + + for(unsigned v = 0; v < height; v += 4) { + uint32 *dest = &tex->image[tex->width*v]; + + for(unsigned u = 0; u < width; u += 4) { + // Retrieve 4x4 block = 16 pixels x 2bpp = 32 bits + auto &page = system.vmap.tex[taddr>>14 & 31]; + uint32 block = page[taddr] | page[taddr+2]<<16; + + // Retrieve color selection and mode bits + uint16 colorsel = system.vmap.tex[caddr>>14 & 31][caddr]; + uint32 paddr = tex->colorBase + (4*colorsel & 0xfffc); + uint32 fields = 31<<20 | 31<<10 | 31<<0; + uint32 gap = 15; // space apart to allow averaging + + // This could potentially span most of the palette space, but that would + // complicate the game's texture allocation, so rather unlikely. + tex->colorRange[0] = min(tex->colorRange[0], paddr+0); + tex->colorRange[1] = max(tex->colorRange[1], paddr+8); + + uint32 alpha[4] = { 31, 31, 31, 31 }; + + uint32 colors[4] = { + uint15(system.vmap.texpal[paddr+0 >> 14 & 31][paddr+0]) * (1<> 14 & 31][paddr+2]) * (1<> 14 & 31][paddr+4]) * (1<> 14 & 31][paddr+6]) * (1<> 14) { + case 3: // 2 colors (4-way mix) + colors[2] = (5*colors[0] + 3*colors[1])/8 & fields; + colors[3] = (3*colors[0] + 5*colors[1])/8 & fields; + case 2: // 4 colors (separate) + break; + + case 1: // 2 colors (3-way mix) + transparent + colors[2] = (4*colors[0] + 4*colors[1])/8 & fields; + case 0: // 3 colors (separate) + transarent + alpha[3] = 0; + break; + } + + for(int i = 0; i < 4; i++) { + colors[i] |= colors[i] >> gap; + colors[i] = alpha[i]<<15 | colors[i] & 0x7fff; + } + for(int sv = 0; sv < 4; sv++, dest += tex->width) { + for(int su = 0; su < 4; su++, block >>= 2) + dest[su] = colors[block & 3]; + } + dest += 4 - 4*tex->width; + taddr += 4; + caddr += 2; + } + } +} + +void GPU::convertI2(Texture *tex, int width, int height, bool colorKey) { + tex->texelRange[1] += width*height/4; + tex->colorRange[1] += 8; + + for(unsigned v = 0; v < height; v++) { + uint32 *dest = &tex->image[tex->width*v]; + uint32 taddr = tex->imageBase + width/4*v; + + for(unsigned u = 0; u < width; u++, taddr += !(u%4)) { + uint2 index = system.vmap.tex[taddr>>14 & 31][taddr] >> 2*(u&7); + uint32 paddr = tex->colorBase + 2*index; + uint16 bgr = system.vmap.texpal[paddr>>14 & 31][paddr]; + uint5 a = 31*(colorKey == false || index > 0); + + *dest++ = a<<15 | bgr; + } + } +} + +void GPU::convertI3(Texture *tex, int width, int height) { + tex->texelRange[1] += width*height/1; + tex->colorRange[1] += 16; + + for(unsigned v = 0; v < height; v++) { + uint32 *dest = &tex->image[tex->width*v]; + uint32 taddr = tex->imageBase + width*v; + + for(unsigned u = 0; u < width; u++, taddr++) { + uint8 index = system.vmap.tex[taddr>>14 & 31][taddr] >> 8*(u&1); + uint32 paddr = tex->colorBase + 2*(index & 0x07); + uint16 bgr = system.vmap.texpal[paddr>>14 & 31][paddr]; + uint5 a = index>>3; + + *dest++ = a<<15 | bgr; + } + } +} + +void GPU::convertI4(Texture *tex, int width, int height, bool colorKey) { + tex->texelRange[1] += width*height/2; + tex->colorRange[1] += 32; + + for(unsigned v = 0; v < height; v++) { + uint32 *dest = &tex->image[tex->width*v]; + uint32 taddr = tex->imageBase + width/2*v; + + for(unsigned u = 0; u < width; u++, taddr += !(u%2)) { + uint4 index = system.vmap.tex[taddr>>14 & 31][taddr] >> 4*(u&3); + uint32 paddr = tex->colorBase + 2*index; + uint16 bgr = system.vmap.texpal[paddr>>14 & 31][paddr]; + uint5 a = 31*(colorKey == false || index > 0); + + *dest++ = a<<15 | bgr; + } + } +} + +void GPU::convertI5(Texture *tex, int width, int height) { + tex->texelRange[1] += width*height/1; + tex->colorRange[1] += 64; + + for(unsigned v = 0; v < height; v++) { + uint32 *dest = &tex->image[tex->width*v]; + uint32 taddr = tex->imageBase + width*v; + + for(unsigned u = 0; u < width; u++, taddr++) { + uint8 index = system.vmap.tex[taddr>>14 & 31][taddr] >> 8*(u&1); + uint32 paddr = tex->colorBase + 2*(index & 0x1f); + uint16 bgr = system.vmap.texpal[paddr>>14 & 31][paddr]; + uint5 a = (index>>5) * 9/2; + + *dest++ = a<<15 | bgr; + } + } +} + +void GPU::convertI8(Texture *tex, int width, int height, bool colorKey) { + tex->texelRange[1] += width*height/1; + tex->colorRange[1] += 512; + + for(unsigned v = 0; v < height; v++) { + uint32 *dest = &tex->image[tex->width*v]; + uint32 taddr = tex->imageBase + width*v; + + for(unsigned u = 0; u < width; u++, taddr++) { + uint8 index = system.vmap.tex[taddr>>14 & 31][taddr] >> 8*(u&1); + uint32 paddr = tex->colorBase + 2*index; + uint16 bgr = system.vmap.texpal[paddr>>14 & 31][paddr]; + uint5 a = 31*(colorKey == false || index > 0); + + *dest++ = a<<15 | bgr; + } + } +} + +void GPU::convertARGB(Texture *tex, int width, int height) { + tex->texelRange[1] += width*height*2; + + for(unsigned v = 0; v < height; v++) { + uint32 *dest = &tex->image[tex->width*v]; + uint32 taddr = tex->imageBase + 2*width*v; + + for(unsigned u = 0; u < width; u++, taddr += 2) { + uint16 abgr = system.vmap.tex[taddr>>14 & 31][taddr]; + uint5 a = 31*(abgr >> 15); + + *dest++ = a<<15 | abgr; + } + } +} \ No newline at end of file diff --git a/bsnes/nds/interface/interface.cpp b/bsnes/nds/interface/interface.cpp new file mode 100644 index 00000000..42cf40ce --- /dev/null +++ b/bsnes/nds/interface/interface.cpp @@ -0,0 +1,410 @@ +#include +#include + +namespace NintendoDS { + +Interface *interface = nullptr; + +double Interface::videoFrequency() { + return 2.*33513982 / (2*6 * 263*355); +} + +double Interface::audioFrequency() { + return 2.*33513982 / (2 * 1024); +} + +bool Interface::loaded() { + return true; +} + +unsigned Interface::group(unsigned id) { + if(id == ARM7BIOS || id == ARM9BIOS) return 0; + if(id == Firmware || id == Clock) return 0; + + if(id == Slot1ROM || id == Slot1EEPROM) return 1; + if(id == Slot1FRAM || id == Slot1Flash) return 1; + + if(id == Slot2ROM || id == Slot2RAM) return 2; + if(id == Slot2SRAM || id == Slot2EEPROM) return 2; + if(id == Slot2FRAM || id == Slot2Flash) return 2; + + return 0; +} + +void Interface::load(unsigned id, const string& manifest) { + //print(manifest,"\n"); + string syspath = interface->path(System); + + if(id == NintendoDS) { + gameManifest = manifest; + systemManifest.readfile({syspath, "manifest.xml"}); + XML::Document sysdoc(systemManifest); + + if(!sysdoc["system"].exists()) { + interface->notify("manifest.xml not found"); + } + else { + auto &sys = sysdoc["system"]; + + string arm7BiosFile = sys["arm7"]["bios"]["data"].data; + string arm9BiosFile = sys["arm9"]["bios"]["data"].data; + string firmwareFile = sys["flash"]["data"].data; + string clockXmlFile = sys["rtc"]["data"].data; + + if(!file::exists({syspath, arm7BiosFile})) interface->notify("arm7 bios not found"); + if(!file::exists({syspath, arm9BiosFile})) interface->notify("arm9 bios not found"); + if(!file::exists({syspath, firmwareFile})) interface->notify("firmware not found"); + + interface->loadRequest(ARM7BIOS, arm7BiosFile); + interface->loadRequest(ARM9BIOS, arm9BiosFile); + interface->loadRequest(Firmware, firmwareFile); + interface->loadRequest(Clock, clockXmlFile); + } + + if(gameManifest == "") { + // Default to 1GB ROM with no save. Since GameCard does bounds-check, + // we only allocate enough to hold the stream passed in. + gameManifest = + "" + "" + "" + "" + ""; + } + + // + XML::Document document(gameManifest); + + //if(document.error != "") { + // print(document.error,"\n"); + // return; + //} + + auto &eslot1 = document["cartridge"]["slot1"]; + + // + if(eslot1.exists()) { + // + if(eslot1["rom"].exists()) { + string file = string(eslot1["rom"]["name"].data); + uint32 size = numeral(eslot1["rom"]["size"].data); + uint32 chipId = numeral(eslot1["rom"]["id"].data); + + print("Loading slot-1 ROM (", file, ").. "); + slot1.load(new GameCard(chipId)); + interface->loadRequest(Slot1ROM, file); + print("\n"); + } + // + if(eslot1["save"].exists()) { + string file = string(eslot1["save"]["name"].data); + string type = string(eslot1["save"]["type"].data); + uint32 size = numeral(eslot1["save"]["size"].data); + uint32 psize = numeral(eslot1["save"]["page"].data); // EEPROM only + uint32 chipId = numeral(eslot1["save"]["id"].data); // Flash only + + unsigned id = 0; + if(auto card = slot1.card) { + if(type == "EEPROM") id = Slot1EEPROM, card->spi = new EEPROM(size, psize); + if(type == "Flash") id = Slot1Flash, card->spi = new Flash(size, chipId); + if(type == "FRAM") id = Slot1FRAM, card->spi = new FRAM(size); + } + if(id) { + print("Loading slot-1 ",eslot1["save"]["type"].data," (", file, ").. "); + interface->loadRequest(id, file); + print("\n"); + } + } + // + if(eslot1["irport"].exists()) { + // Required by Pokemon HG/SS and B/W. These cards have an infrared port + // built-in. Since there's only one /CS, access to flash memory passes + // through the infrared bridge via an override command. + slot1.card->spi = new IRPort(slot1.card->spi); + } + } + } + + // Provide blank images if needed (we'd crash otherwise). + if(system.firmware.size == 0) { + system.firmware.size = 0x40000; + system.firmware.data = new uint8[system.firmware.size]; + memset(system.firmware.data, 0xff, system.firmware.size); + } + if(arm7.bios.size == 0) { + arm7.bios.size = 4; + arm7.bios.data = new uint32[arm7.bios.size/4]; + memset(arm7.bios.data, 0xef, arm7.bios.size); + } + if(arm9.bios.size == 0) { + arm9.bios.size = 4; + arm9.bios.data = new uint32[arm9.bios.size/4]; + memset(arm9.bios.data, 0xef, arm9.bios.size); + } +} + +void Interface::load(unsigned id, const stream& memory, const string& markup) { + if(id == ARM7BIOS) return system.loadArm7Bios(memory); + if(id == ARM9BIOS) return system.loadArm9Bios(memory); + if(id == Firmware) return system.loadFirmware(memory); + if(id == Clock) return system.loadRTC(memory); + + XML::Document document(gameManifest); + + auto &eslot1 = document["cartridge"]["slot1"]; + + if(eslot1.exists()) { + if(eslot1["rom"].exists() && id == Slot1ROM) { + string hash = string(eslot1["rom"]["sha256"].data); + uint32 size = numeral(eslot1["rom"]["size"].data); + + if(auto card = slot1.card) { + delete card->rom.data; + card->rom.size = min(memory.size(), size); + card->rom.data = new uint8[card->rom.size]; + card->size = bit::round(size); + + memory.read(card->rom.data, card->rom.size); + + if(hash && hash != card->sha256) print("SHA256 mismatch."); + else print("OK."); + } + } + if(eslot1["save"].exists() && slot1.card && (id==Slot1EEPROM || id==Slot1Flash || id==Slot1FRAM)) { + uint32 size = numeral(eslot1["save"]["size"].data); + + if(auto save = slot1.card->spi) { + if(auto irport = dynamic_cast(save)) + save = irport->slave; + + if(auto media = dynamic_cast(save)) { + memory.read(media->data, min(media->size, memory.size())); + print("OK."); + } + } + } + } +} + + + +void Interface::save() { + XML::Document sysdoc(systemManifest); + + if(sysdoc["system"].exists()) { + auto &sys = sysdoc["system"]; + + interface->saveRequest(Firmware, sys["flash"]["data"].data); + interface->saveRequest(Clock, sys["rtc"]["data"].data); + } + + XML::Document document(gameManifest); + auto &eslot1 = document["cartridge"]["slot1"]; + + if(eslot1.exists() && eslot1["save"].exists()) { + string file = eslot1["save"]["name"].data; + string type = eslot1["save"]["type"].data; + + print("Saving slot-1 ",type,".. "); + + if(type == "EEPROM") interface->saveRequest(Slot1EEPROM, file); + if(type == "Flash") interface->saveRequest(Slot1Flash, file); + if(type == "FRAM") interface->saveRequest(Slot1FRAM, file); + + print("\n"); + } +} + +void Interface::save(unsigned id, const stream& memory) { + if(id == Firmware) return system.saveFirmware(memory); + if(id == Clock) return system.saveRTC(memory); + + if(slot1.card && (id == Slot1EEPROM || id == Slot1Flash || id == Slot1FRAM)) { + if(auto save = slot1.card->spi) { + if(auto irport = dynamic_cast(save)) + save = irport->slave; + + if(auto media = dynamic_cast(save)) { + memory.write(media->data, media->size); + print("OK."); + } + } + } +} + + + +void Interface::unload() { + struct timeval tv; + gettimeofday(&tv, nullptr); + system.clock.freeze(tv.tv_sec, tv.tv_usec); + system.running = false; + + save(); + delete slot1.unload(); +} + +void Interface::power() { + system.power(); +} + +void Interface::run() { + if(!system.running) { + struct timeval tv; + gettimeofday(&tv, nullptr); + system.clock.thaw(tv.tv_sec, tv.tv_usec); + system.running = true; + } + system.run(); +} + +serializer Interface::serialize() { + return {}; +} + +bool Interface::unserialize(serializer &s) { + return false; +} + +void Interface::paletteUpdate() { + for(unsigned color = 0; color < 01000000; color++) { + uint16 r = uint6(color>> 0) * 010101/4; + uint16 g = uint6(color>> 6) * 010101/4; + uint16 b = uint6(color>>12) * 010101/4; + + palette[color] = interface->videoColor(color, r,g,b); + } +} + +void Interface::videoRefresh(const uint32_t *data, unsigned pitch, unsigned width, unsigned height) { + static uint32_t pixels[256*384]; + + for(unsigned y = 0; y < 384; y++) { + const uint32 *src = &data[y*pitch/4]; + uint32 *dest = &pixels[y*256]; + + for(unsigned x = 0; x < 256; x++) + dest[x] = palette[src[x] & 0777777]; + } + return bind->videoRefresh(pixels, 256*4, 256, 384); +} + + +Interface::Interface() { + interface = this; + + information.name = "Nintendo DS"; + information.width = 256; + information.height = 384; + information.aspectRatio = 1.0; + information.overscan = false; + information.resettable = false; + information.capability.states = false; + information.capability.cheats = false; + + media.append({NintendoDS, "Nintendo DS", "nds"}); + //media.append({NintendoDS, "Nintendo DS", "nds", "Menu"}); + + // Input devices and ports + + emptySlot = Device{ID::Device::Empty, 1<port) + for(auto &device : this->device) + if(device.portmask & 1< device; + + // System inputs + Device sensors; + Device buttons; + Device touchpad; + + Device emptySlot; + + // Slot 1 + Device gameCard; + + // Slot 2 peripherals + Device gamePak; // for linking Pokémon D/P/HG/SS and R/S/E + Device expansionPak; // Opera browser, homebrew + Device rumblePak; // Metroid Pinball, others + Device guitarGrip; // Guitar Hero: On Tour + Device piano; // Easy Piano + Device paddle; // Arkanoid + + unsigned palette[01000000]; +}; + +extern Interface *interface; + +#ifndef NDS_HPP +} +#endif diff --git a/bsnes/nds/memory/eeprom.cpp b/bsnes/nds/memory/eeprom.cpp new file mode 100644 index 00000000..cdb873f0 --- /dev/null +++ b/bsnes/nds/memory/eeprom.cpp @@ -0,0 +1,96 @@ + +EEPROM::~EEPROM() { } + +EEPROM::EEPROM(uint32 esize, uint32 psize) { + data = new uint8[size = esize]; + pageSize = psize; + memset(data, 0xff, size); +} + +EEPROM::EEPROM(const stream& memory, uint32 esize, uint32 psize) { + data = new uint8[size = esize]; + pageSize = psize; + memset(data, 0xff, size); + memory.read(data, min(memory.size(), size)); +} + +void EEPROM::power() { + if(!pageSize) { + if(size <= 0x200) pageSize = 0x10; + else if(size <= 0x2000) pageSize = 0x20; + else pageSize = 0x80; + } + command = 0; + writeEnable = false; +} + +void EEPROM::select(bool state) { + if(state) return; + + if(command && writeEnable) { + // Finish some previously submitted commands + if(command == 0x02 || command == 0x0a) { + //print("finishing write to ",hex<6>(page),"\n"); + address = page; + + // Write page + for(unsigned n = 0; n < count; n++) { + if(!(address & pageSize-1)) address = page; + this->data[address++] = buffer[n]; + } + writeEnable = false; + } + } + // Reset and wait for a new command + command = 0; +} + +uint8 EEPROM::transfer(uint8 data) { + if(command == 0) { + command = data; + address = count = 0; + addrCount = 0; + + //print("eeprom: cmd ",hex<2>(command),"\n"); + if(command == 0x02 || command == 0x0a) addrCount = 1 + (size > 512); + if(command == 0x03 || command == 0x0b) addrCount = 1 + (size > 512); + + if(command == 0x0a && size == 512) address = 1; // read/write 2nd page + if(command == 0x0b && size == 512) address = 1; // (512-byte only) + + if(command == 0x04) writeEnable = false; + if(command == 0x06) writeEnable = true; + return 0xff; + } + + if(addrCount) { // Input address + addrCount--; + address = address<<8 | data; + page = address; + return 0xff; + } + + if(command == 0x01) { + return 0xff; // Write status + } + + if(command == 0x05) { // Read status + return (size > 512? 0x00 : 0xf0) | writeEnable<<1; // | writing<<0; + } + + if(command == 0x03 || command == 0x0b) { // Read data + //if(address == page) print("eeprom: read ",hex<6>(address),"\n"); + if(address == size) address = 0; + return this->data[address++]; + } + + if(command == 0x02 || command == 0x0a) { // Write data + //if(address == page) print("eeprom: write ",hex<6>(address),"\n"); + if(count < pageSize) { + if(!(address & pageSize-1)) address = page; + buffer[count++] = data; + return this->data[address++]; + } + } + return 0xff; +} diff --git a/bsnes/nds/memory/eeprom.hpp b/bsnes/nds/memory/eeprom.hpp new file mode 100644 index 00000000..248390a1 --- /dev/null +++ b/bsnes/nds/memory/eeprom.hpp @@ -0,0 +1,17 @@ + +struct EEPROM : SPIDevice, StaticMemory { + ~EEPROM(); + EEPROM(uint32 esize, uint32 psize); + EEPROM(const stream& memory, uint32 esize, uint32 psize); + + void power(); + void select(bool state); + uint8 transfer(uint8 data); + + uint8 command; + uint16 address, page, pageSize; + unsigned addrCount; + unsigned count; + uint8 buffer[256]; + bool writeEnable; +}; diff --git a/bsnes/nds/memory/flash.cpp b/bsnes/nds/memory/flash.cpp new file mode 100644 index 00000000..15bcb572 --- /dev/null +++ b/bsnes/nds/memory/flash.cpp @@ -0,0 +1,137 @@ + +Flash::~Flash() { } + +Flash::Flash(uint32 esize, uint32 id) { + data = new uint8[size = esize]; + memset(data, 0xff, size); + this->id = id; +} + +Flash::Flash(const stream& memory, uint32 esize, uint32 id) { + data = new uint8[size = esize]; + memset(data, 0xff, size); + memory.read(data, min(memory.size(), size)); + this->id = id; +} + +void Flash::power() { + powered = true; + command = 0; + writeEnable = false; +} + +void Flash::select(bool state) { + if(state) return; + + //print("flash: deselect - cmd=",hex<2>(command)," wen=",writeEnable,"\n"); + if(command && writeEnable) { + // Finish some previously submitted commands + if(command == 0x0a) { + // Read any remaining page into the buffer, + // so it's not lost during the erase cycle. + while(count < 256) { + buffer[count++] = data[address++]; + if(!(address & 0xff)) address -= 0x100; + } + } + + if(command == 0x0a || command == 0xdb || command == 0xd8) { + // Modify page / erase page / erase 64Kbyte sector + unsigned block = command == 0xd8? 0x10000 : 0x100; + + address = page & ~(block-1); + + // Erasing sets data bits to 1. + for(unsigned n = 0; n < block; n++) + data[address++] = 0xff; + + writeEnable = false; + } + + if(command == 0x0a || command == 0x02) { + // Modify page / write page + address = page; + //print("finishing write to ",hex<6>(page),"\n"); + + for(unsigned n = 0; n < 256; n++) { + // Writing can only clear bits. + data[address++] &= buffer[n]; + if(!(address & 0xff)) address -= 0x100; + } + writeEnable = false; + } + } + // Reset and wait for a new command + command = 0; +} + +uint8 Flash::transfer(uint8 data) { + if(command == 0) { + command = data; + count = 0; + address = 0; + addrCount = 0; + + //print("flash: cmd ",hex<2>(command),"\n"); + + if(command == 0xab) powered = true; // Wake up + + if(powered) { + if(command == 0x9f) count = 3; // Read ID + if(command == 0xb9) powered = false; // Power down + if(command == 0x06) writeEnable = true; // Write enable + if(command == 0x04) writeEnable = false; // Write disable + + if(command == 0xdb || command == 0xd8) addrCount = 3; // Erase page / sector + if(command == 0x02 || command == 0x0a) addrCount = 3; // Write data + if(command == 0x03 || command == 0x0b) addrCount = 3; // Read data + } + return 0; + } + if(!powered) + return 0; + + if(addrCount) { + // Input address + addrCount--; + address = address<<8 | data; + page = address; + if(command == 0x0b) count = 1; // Dummy byte between address and data + return 0; + } + + if(command == 0x9f) { + // Read ID + //print("flash: read id\n"); + if(count) count--; + return id >> 8*count; + } + + if(command == 0x05) { + // Read status + //print("flash: read status\n"); + return writeEnable<<1; // | writing<<0; + } + + if(command == 0x03 || command == 0x0b) { + // Read data + //if(address == page) print("flash: read ",hex<6>(address),"\n"); + if(count) { count--; return 0; } + if(address >= size) address = 0; + return this->data[address++]; + } + + if(command == 0x02 || command == 0x0a) { + // Write page / modify page + //if(address == page) print("flash: write ",hex<6>(address),"\n"); + if(count < 0x100) { + if(address >= size) address = 0; + buffer[count++] = data; + uint8 r = this->data[address++]; + if(!(address & 0xff)) address -= 0x100; + return r; + } + return 0; + } + return 0; +} diff --git a/bsnes/nds/memory/flash.hpp b/bsnes/nds/memory/flash.hpp new file mode 100644 index 00000000..32656344 --- /dev/null +++ b/bsnes/nds/memory/flash.hpp @@ -0,0 +1,20 @@ + +struct Flash : SPIDevice, StaticMemory { + ~Flash(); + Flash() {} + Flash(uint32 esize, uint32 id); + Flash(const stream& memory, uint32 esize, uint32 id); + + void power(); + void select(bool state); + uint8 transfer(uint8 data); + + uint24 id; + uint8 command; + uint24 address, page; + unsigned addrCount; + unsigned count; + uint8 buffer[256]; + bool powered; + bool writeEnable; +}; diff --git a/bsnes/nds/memory/fram.cpp b/bsnes/nds/memory/fram.cpp new file mode 100644 index 00000000..1e955bd6 --- /dev/null +++ b/bsnes/nds/memory/fram.cpp @@ -0,0 +1,64 @@ + +FRAM::~FRAM() { } + +FRAM::FRAM(uint32 esize) { + data = new uint8[size = esize]; + memset(data, 0xff, size); +} + +FRAM::FRAM(const stream& memory, uint32 esize) { + data = new uint8[size = esize]; + memset(data, 0xff, size); + memory.read(data, min(memory.size(), size)); +} + +void FRAM::power() { + command = 0; + writeEnable = false; +} + +void FRAM::select(bool state) { + if(state) return; + + // Reset and wait for a new command + if(command == 0x02) writeEnable = false; + command = 0; +} + +uint8 FRAM::transfer(uint8 data) { + if(command == 0) { + command = data; + address = addrCount = 0; + + if(command == 0x02) addrCount = 2; + if(command == 0x03) addrCount = 2; + if(command == 0x04) writeEnable = false; + if(command == 0x06) writeEnable = true; + return 0xff; + } + + if(addrCount) { // Input address + addrCount--; + address = address<<8 | data; + return 0xff; + } + + if(command == 0x01) { + return 0xff; // Write status + } + + if(command == 0x05) { // Read status + return writeEnable<<1; // | writing<<0; + } + + if(command == 0x03) { // Read data + if(address == size) address = 0; + return this->data[address++]; + } + + if(command == 0x02) { // Write data + if(address == size) address = 0; + return this->data[address++] = data; + } + return 0xff; +} diff --git a/bsnes/nds/memory/fram.hpp b/bsnes/nds/memory/fram.hpp new file mode 100644 index 00000000..753f2a29 --- /dev/null +++ b/bsnes/nds/memory/fram.hpp @@ -0,0 +1,16 @@ + +struct FRAM : SPIDevice, StaticMemory { + ~FRAM(); + FRAM(uint32 esize); + FRAM(const stream& memory, uint32 esize); + + void power(); + void select(bool state); + uint8 transfer(uint8 data); + + uint8 command; + uint16 address, page, pageSize; + unsigned addrCount; + uint8 buffer[256]; + bool writeEnable; +}; diff --git a/bsnes/nds/memory/memory.cpp b/bsnes/nds/memory/memory.cpp new file mode 100644 index 00000000..e4e10d44 --- /dev/null +++ b/bsnes/nds/memory/memory.cpp @@ -0,0 +1,127 @@ +#include + +namespace NintendoDS { + +Memory::~Memory() {} + +struct UnmappedMemory : Memory { + uint32 read(uint32 addr, uint32 size) { return 0u; } + void write(uint32 addr, uint32 size, uint32 word) {} +}; + +static UnmappedMemory unmappedMemory; + + +StaticMemory::StaticMemory() { data = nullptr; size = 0u; } +StaticMemory::~StaticMemory() { if(data) delete[] data; } +uint8& StaticMemory::operator[](uint32 addr) { return data[addr]; } + +uint32 StaticMemory::read(uint32 addr, uint32 size) { + if(size == Byte) return (*this)[addr]; + if(size == Half) return addr &= ~1, (*this)[addr] | (*this)[addr+1]<<8; + if(size == Word) return addr &= ~3, (*this)[addr] | (*this)[addr+1]<<8 | (*this)[addr+2]<<16 | (*this)[addr+3]<<24; +} + +void StaticMemory::write(uint32 addr, uint32 size, uint32 word) { + if(size == Half) addr &= ~1; + if(size == Word) addr &= ~3; + + (*this)[addr] = word; + if(size >= Half) { + (*this)[addr+1] = word>>8; + } + if(size >= Word) { + (*this)[addr+2] = word>>16; + (*this)[addr+3] = word>>24; + } +} + + +ByteMemory::ByteMemory() { data = nullptr; size = 0u; } +ByteMemory::~ByteMemory() { if(data) delete[] data; } +uint8& ByteMemory::operator[](uint32 addr) { return data[addr]; } + +uint32 ByteMemory::read(uint32 addr, uint32 size) { + return (*this)[addr] * 0x01010101; +} + +void ByteMemory::write(uint32 addr, uint32 size, uint32 word) { + (*this)[addr] = word; +} + + +HalfMemory::HalfMemory() { data = nullptr; size = 0u; } +HalfMemory::~HalfMemory() { if(data) delete[] data; } + +uint16& HalfMemory::operator[](uint32 addr) { return data[addr>>1]; } + +uint32 HalfMemory::read(uint32 addr, uint32 size) { + if(size == Word) return addr &= ~3, (*this)[addr] + ((*this)[addr+2] << 16); + if(size != Word) return (*this)[addr] * 0x00010001; +} + +void HalfMemory::write(uint32 addr, uint32 size, uint32 word) { + if(size == Word) addr &= ~3; + + (*this)[addr] = word; + if(size == Word) + (*this)[addr+2] = word>>16; +} + + +WordMemory::WordMemory() { data = nullptr; size = 0u; } +WordMemory::~WordMemory() { if(data) delete[] data; } + +uint32& WordMemory::operator[](uint32 addr) { return data[addr>>2]; } + +uint32 WordMemory::read(uint32 addr, uint32 size) { + return (*this)[addr]; +} + +void WordMemory::write(uint32 addr, uint32 size, uint32 word) { + if(size == Word) (*this)[addr] = word; + if(size != Word) (*this)[addr] ^= ((*this)[addr] ^ word) & 0xffff << 8*(addr & 2); +} + + +SDRAM::SDRAM() { data = nullptr; size = 0u; } +SDRAM::~SDRAM() { if(data) delete[] data; } + +uint16& SDRAM::operator[](uint32 addr) { return data[addr>>1]; } + +uint32 SDRAM::read(uint32 addr, uint32 size) { + if(size == Word) return addr &= ~3, (*this)[addr] + ((*this)[addr+2] << 16); + if(size != Word) return (*this)[addr] * 0x00010001; +} + +void SDRAM::write(uint32 addr, uint32 size, uint32 word) { + if(size == Word) { + addr &= ~3; + (*this)[addr+0] = word; + (*this)[addr+2] = word>>16; + } + if(size == Half) (*this)[addr] = word; + if(size == Byte) (*this)[addr] ^= ((*this)[addr] ^ word) & 0xff << 8*(addr & 1); +} + + +SRAM::SRAM() { data = nullptr; size = 0u; } +SRAM::~SRAM() { if(data) delete[] data; } + +uint32& SRAM::operator[](uint32 addr) { return data[addr>>2]; } + +uint32 SRAM::read(uint32 addr, uint32 size) { + return (*this)[addr]; +} + +void SRAM::write(uint32 addr, uint32 size, uint32 word) { + if(size == Word) (*this)[addr] = word; + if(size == Half) (*this)[addr] ^= ((*this)[addr] ^ word) & 0xffff << 8*(addr & 2); + if(size == Byte) (*this)[addr] ^= ((*this)[addr] ^ word) & 0xff << 8*(addr & 3); +} + +#include "eeprom.cpp" +#include "fram.cpp" +#include "flash.cpp" + +} diff --git a/bsnes/nds/memory/memory.hpp b/bsnes/nds/memory/memory.hpp new file mode 100644 index 00000000..b1f2ed7f --- /dev/null +++ b/bsnes/nds/memory/memory.hpp @@ -0,0 +1,76 @@ +struct Memory { + virtual ~Memory(); + virtual uint32 read(uint32 addr, uint32 size) = 0; + virtual void write(uint32 addr, uint32 size, uint32 word) = 0; +}; + +struct StaticMemory : Memory { + uint8_t *data; + unsigned size; + + uint8& operator[](uint32 addr); + uint32 read(uint32 addr, uint32 size); + void write(uint32 addr, uint32 size, uint32 word); + StaticMemory(); + ~StaticMemory(); +}; + +// Slot 2 SRAM - 8-bit; bytes only +struct ByteMemory : Memory { + uint8_t *data; + unsigned size; + + uint8& operator[](uint32 addr); + uint32 read(uint32 addr, uint32 size); + void write(uint32 addr, uint32 size, uint32 word); + ByteMemory(); + ~ByteMemory(); +}; + +// VRAM, Palettes - 16-bit; halves and words +struct HalfMemory : Memory { + uint16_t *data; + unsigned size; + + uint16& operator[](uint32 addr); + uint32 read(uint32 addr, uint32 size); + void write(uint32 addr, uint32 size, uint32 word); + HalfMemory(); + ~HalfMemory(); +}; + +// OAM, BIOS - 32-bit; halves and words +struct WordMemory : Memory { + uint32_t *data; + unsigned size; + + uint32& operator[](uint32 addr); + uint32 read(uint32 addr, uint32 size); + void write(uint32 addr, uint32 size, uint32 word); + WordMemory(); + ~WordMemory(); +}; + +// EWRAM - 16-bit; all sizes +struct SDRAM : Memory { + uint16_t *data; + unsigned size; + + uint16& operator[](uint32 addr); + uint32 read(uint32 addr, uint32 size); + void write(uint32 addr, uint32 size, uint32 word); + SDRAM(); + ~SDRAM(); +}; + +// TCM, IWRAM - 32-bit; all sizes +struct SRAM : Memory { + uint32_t *data; + unsigned size; + + uint32& operator[](uint32 addr); + uint32 read(uint32 addr, uint32 size); + void write(uint32 addr, uint32 size, uint32 word); + SRAM(); + ~SRAM(); +}; diff --git a/bsnes/nds/nds.hpp b/bsnes/nds/nds.hpp new file mode 100644 index 00000000..72f7d9ae --- /dev/null +++ b/bsnes/nds/nds.hpp @@ -0,0 +1,29 @@ +#ifndef NDS_HPP +#define NDS_HPP + +// dasShiny - Nintendo DS emulator +// Copyright (c) 2012 Cydrak +// License: GPLv3 + +#include +#include + +namespace NintendoDS { + enum : unsigned { + Byte = 8, Half = 16, Word = 32 + }; + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +} + +#endif diff --git a/bsnes/nds/ppu/bg.cpp b/bsnes/nds/ppu/bg.cpp new file mode 100644 index 00000000..401d0e35 --- /dev/null +++ b/bsnes/nds/ppu/bg.cpp @@ -0,0 +1,251 @@ + +void PPU::renderBgs(unsigned y) { + unsigned bpp[4] = {}; + unsigned mapw[4], maph[4]; // tiled dimensions + unsigned affw[4], affh[4]; // Affine dimensions + unsigned bitw[4], bith[4]; // Bitmap dimensions + + for(unsigned n = 0; n < 4; n++) { + // Tiled dimensions + mapw[n] = bg[n].size & 1? 64 : 32; + maph[n] = bg[n].size & 2? 64 : 32; + + // Affine settings + affw[n] = 16 << bg[n].size; + affh[n] = 16 << bg[n].size; + bitw[n] = 128 << (bg[n].size - (bg[n].size >= 3)); // 128,256,512,512 + bith[n] = 128 << (bg[n].size - (bg[n].size >= 2)); // 128,256,256,512 + bpp[n] = 8 << (bg[n].tiles & 1); + } + + if(video.line == 0) { + bg[2].linex = bg[2].originx; + bg[2].liney = bg[2].originy; + bg[3].linex = bg[3].originx; + bg[3].liney = bg[3].originy; + } + + if(bgMode == 6) { + // Large 512 x 1024 x 8bpp bitmap - uses all 512K BG + // Supposedly 3D is still available on BG0, though + // you'd have no VRAM leftover for textures... + bitw[2] = 512 << (bg[2].size & 1); + bith[2] = 1024 >> (bg[2].size & 1); + + renderBitmapBg(2, 8, bitw[2], bith[2], y); + } + else { + // BG0 is either tiled or 3D render output + // BG1 is always tiled + if(bg0FromGPU == 0) renderTiledBg (0, mapw[0], maph[0], y); + renderTiledBg (1, mapw[1], maph[1], y); + + // BG2-3 are a selectable mix of: + // - Tiled: 16-bit screen blocks with tile attributes + // - GBA: 8-bit affine maps, only tile number + // - NDS: 16-bit affine maps with tile attributes; + // these also work as 8/16-bpp bitmaps + // + if(bgMode == 0) { // 2 x tiled + renderTiledBg (2, mapw[2], maph[2], y); + renderTiledBg (3, mapw[3], maph[3], y); + } + if(bgMode == 1) { // Tiled + GBA + renderTiledBg (2, mapw[2], maph[2], y); + renderAffineBg(3, 8, affw[3], affh[3], y); + } + if(bgMode == 2) { // 2 x GBA + renderAffineBg(2, 8, affw[2], affh[2], y); + renderAffineBg(3, 8, affw[3], affh[3], y); + } + if(bgMode == 3) { // Tiled + NDS + renderTiledBg (2, mapw[2], maph[2], y); + if(bg[3].depth == 0) renderAffineBg(3, 16, affw[3], affh[3], y); + if(bg[3].depth == 1) renderBitmapBg(3, bpp[3], bitw[3], bith[3], y); + } + if(bgMode == 4) { // GBA + NDS + renderAffineBg(2, 8, affw[2], affh[2], y); + if(bg[3].depth == 0) renderAffineBg(3, 16, affw[3], affh[3], y); + if(bg[3].depth == 1) renderBitmapBg(3, bpp[3], bitw[3], bith[3], y); + } + if(bgMode == 5) { // 2 x NDS + if(bg[2].depth == 0) renderAffineBg(2, 16, affw[2], affh[2], y); + if(bg[3].depth == 0) renderAffineBg(3, 16, affw[3], affh[3], y); + if(bg[2].depth == 1) renderBitmapBg(2, bpp[2], bitw[2], bith[2], y); + if(bg[3].depth == 1) renderBitmapBg(3, bpp[3], bitw[3], bith[3], y); + } + } + + bg[2].linex += bg[2].transform.dx_dv; + bg[2].liney += bg[2].transform.dy_dv; + bg[3].linex += bg[3].transform.dx_dv; + bg[3].liney += bg[3].transform.dy_dv; +} + +void PPU::renderTiledBg(unsigned no, unsigned mapw, unsigned maph, unsigned y) { + auto &bg = this->bg[no]; + if(bg.enable == false) + return; + + uint32 flags = pxPriority*bg.priority + pxLayer*(2u+no); + unsigned line = bg.voffs + y; + unsigned finex = bg.hoffs % 8; + auto above = &this->above[8 - finex]; + auto below = &this->below[8 - finex]; + + if(blendAbove & 1< 32 && (mapy & 32)) maddr += 32*mapw; + if(mapw > 32 && (mapx & 32)) maddr += 32*32; + + bool ext = bg.depth && bgLargePal; + unsigned depth = bg.depth? 0x100 : 0x10; + unsigned imask = depth-1; + + unsigned extpalbase = 0x1000*no; + if(bg.affineWrap) // special case for BG0/BG1 - this bit + extpalbase |= 0x2000; // makes them share BG2/BG3's palettes + + for(unsigned x = 0; x < 256+8; ) { + uint16 attr = system.vmap.bg(which, 2*maddr>>14)[2*maddr]; + int pal = (attr>>12)*depth + extpalbase; + uint1 vflip = attr>>11; + uint1 hflip = attr>>10; + uint10 tile = attr; + + int row = line%8; + if(vflip) row ^= 7; + + uint32 taddr = 0x10000*bgTileBase + 0x4000*bg.tiles + ((32*tile + 4*row) << bg.depth); + auto tref = &system.vmap.bg(which, taddr>>14)[taddr]; + + uint64 slice = 0; + for(int n = 3; n >= 0; --n) + slice = slice<<16 | tref[n]; + + int dir = +1; + if(hflip) dir = -1, x += 7; + + for(unsigned n = 0; n < 8; n++, x += dir) { + if(window[x + 8 - finex] & 1<> 13][pal+index << 1]; + bgr = (bgr<<3 & 0760000) | (bgr<<2 & 0007600) | (bgr<<1 & 0000076); + } + if(flags < above[x]) below[x] = above[x], above[x] = flags + bgr; + else if(flags < below[x]) below[x] = flags + bgr; + } + } + slice >>= (4 << bg.depth); + } + + if(hflip) x += 9; + + if((++maddr & 31) == 0) { + maddr -= 32; + if(mapw > 32) // wrap to next screen + maddr += mapx & 32? -32*32 : +32*32; + } + } +} + +void PPU::renderAffineBg(unsigned no, unsigned mapDepth, unsigned mapW, unsigned mapH, unsigned y) { + auto &bg = this->bg[no]; + if(bg.enable == false) + return; + + bool ext = mapDepth==16 && bgLargePal; + uint32 flags = pxPriority*bg.priority + pxLayer*(2+no); + int32 fx = bg.linex; + int32 fy = bg.liney; + + if(blendAbove & 1<> 8; + unsigned my = fy >> 8; + + if(bg.affineWrap) + mx &= 8*mapW-1, my &= 8*mapH-1; + + if(mx < 8*mapW && my < 8*mapH) { + uint32 addr = 0x10000*bgMapBase + 2*32*32*bg.map + ((mapW*(my/8) + (mx/8)) << (mapDepth == 16)); + uint16 attr = system.vmap.bg(which, addr>>14)[addr]; + + if(mapDepth == 8) { + // no special handling - pal, vflip, hflip will all be 0 + attr = attr >> 8*(mx/8 & 1) & 0xff; + } + int pal = (attr>>12)*0x100 + no*0x1000; + uint1 vflip = attr>>11; + uint1 hflip = attr>>10; + uint10 tile = attr; + + int row = my%8 ^ 7*vflip; + int col = mx%8 ^ 7*hflip; + + uint32 taddr = 0x10000*bgTileBase + 0x4000*bg.tiles + 64*tile + 8*row + col; + uint8 index = system.vmap.bg(which, taddr>>14)[taddr] >> 8*(col & 1); + + if(index) { + uint32 bgr = bgPal[pal+index & 0xff]; + if(ext) { + bgr = system.vmap.bgpal[which][pal>>13][pal+index << 1]; + bgr = (bgr<<3 & 0760000) | (bgr<<2 & 0007600) | (bgr<<1 & 0000076); + } + if(flags < above[x]) below[x] = above[x], above[x] = flags + bgr; + else if(flags < below[x]) below[x] = flags + bgr; + } + } + } + fx += bg.transform.dx_dh; + fy += bg.transform.dy_dh; + } +} + +void PPU::renderBitmapBg(unsigned no, unsigned mapDepth, unsigned mapW, unsigned mapH, unsigned y) { + auto &bg = this->bg[no]; + if(bg.enable == false) + return; + + uint32 flags = pxPriority*bg.priority + pxLayer*(2+no); + int32 fx = bg.linex; + int32 fy = bg.liney; + + if(blendAbove & 1<>8, my = fy>>8; + + if(bg.affineWrap) + mx &= mapW-1, my &= mapH-1; + + if(mx < mapW && my < mapH) { + uint32 addr = 0x4000*bg.map + ((mapW*my + mx) << (mapDepth == 16)); + uint16 data = system.vmap.bg(which, addr>>14)[addr] >> 8*(addr & 1); + uint32 bgr; + + if(mapDepth== 8) bgr = bgPal[data &= 0xff]; + if(mapDepth==16) bgr = (data<<3&62<<12)|(data<<2&62<<6)|(data<<1&62), data &= 0x8000; + + if(data) { + if(flags < above[x]) below[x] = above[x], above[x] = flags + bgr; + else if(flags < below[x]) below[x] = flags + bgr; + } + } + } + fx += bg.transform.dx_dh; + fy += bg.transform.dy_dh; + } +} diff --git a/bsnes/nds/ppu/obj.cpp b/bsnes/nds/ppu/obj.cpp new file mode 100644 index 00000000..f1bce309 --- /dev/null +++ b/bsnes/nds/ppu/obj.cpp @@ -0,0 +1,159 @@ + +void PPU::renderObjs(unsigned y) { + if(objEnable == false) + return; + + for(unsigned n = 0; n < 128; n++) { + objinfo& obj = this->obj[n]; + + if(obj.renderMode == objinfo::hidden) continue; + + uint8 width = 1 << obj.size; + uint8 height = 1 << obj.size; + uint8 row = y - obj.y; + + bool wide = obj.shape == objinfo::wide; + bool tall = obj.shape == objinfo::tall; + bool affine = obj.renderMode & objinfo::affine; + bool size = obj.renderMode == objinfo::affineDouble; + + if(obj.size <= 1) width <<= wide, height <<= tall; + if(obj.size >= 1) width >>= tall, height >>= wide; + if(wide && tall) width = 1, height = 1; + + if(row >= 8*(height << size)) continue; + if(obj.x <= -8*(width << size)) continue; + + if(obj.kind == objinfo::bitmap) renderBitmapObj(obj, width, height, row); + else renderTiledObj(obj, width, height, row); + } +} + +void PPU::renderTiledObj(objinfo& obj, unsigned objw, unsigned objh, unsigned y) { + unsigned step = objTileMode? 0+objTileStep : 0; + unsigned srow = objTileMode? objw << obj.depth : 32; + unsigned tile = obj.index << step; + + uint32 zmask = pxPriority*3u + pxLayer*7u; + uint32 flags = pxPriority*obj.priority + pxLayer*1u; + bool affine = obj.renderMode & objinfo::affine; + bool size = obj.renderMode == objinfo::affineDouble; + bool hflip = obj.transform & 8; + bool vflip = obj.transform & 16; + bool ext = obj.depth && objLargePal; + bool win = obj.kind == objinfo::window; + unsigned pal = obj.depth? 256*obj.palette : 16*obj.palette; + unsigned mask = obj.depth? 0xff : 0x0f; + + if(blendAbove & 1<<4) flags |= pxBlendAbove; + if(blendBelow & 1<<4) flags |= pxBlendBelow; + + if(obj.kind == objinfo::blend) flags |= pxBlendForce; + + affineparam tf = { 0x100, 0, 0, 0x100 }; + + int32 cx = 8*objw/2, ox = 0 - (cx << size), dw = 8*objw << size; + int32 cy = 8*objh/2, oy = y - (cy << size), dh = 8*objh << size; + + if(affine) { + tf = objTransform[obj.transform]; + } else { + if(hflip) ox++, tf.dx_dh *= -1; + if(vflip) oy++, tf.dy_dv *= -1; + } + + int32 fx = ox*tf.dx_dh + oy*tf.dx_dv; + int32 fy = ox*tf.dy_dh + oy*tf.dy_dv; + + int x = obj.x + 8; + for(unsigned t = 0; t < dw && x < 256+8; x++, t++) { + uint32 mx = (fx >> 8) + cx; + uint32 my = (fy >> 8) + cy; + + if(mx < 8*objw && my < 8*objh) { + unsigned taddr = tile; + + taddr += (my/8)*srow; + taddr += (mx/8) << obj.depth; taddr <<= 3; + taddr += (my%8) << obj.depth; taddr <<= 2; + taddr += (mx%8) >>!obj.depth; + + uint16 data = system.vmap.obj(which, taddr>>14)[taddr]; + + if(obj.depth) data = data >> 8*(mx%2) & mask; + else data = data >> 4*(mx%4) & mask; + + if(x >= 0 && data) { + if(win) { + window[x] = min(window[x], 0x20+winArea[2]); + } + else { + uint32 bgr = objPal[pal+data & 0xff]; + if(ext) { + bgr = system.vmap.objpal[which][pal>>13][pal+data << 1]; + bgr = (bgr<<3 & 0760000) | (bgr<<2 & 0007600) | (bgr<<1 & 0000076); + } + if(flags < (objLayer[x] & zmask)) objLayer[x] = flags + bgr; + } + } + } + fx += tf.dx_dh; + fy += tf.dy_dh; + } +} + +void PPU::renderBitmapObj(objinfo& obj, unsigned objw, unsigned objh, unsigned y) { + unsigned srow = objBitmapMode>1? 16*objw : 256<1) tile <<= 7+objBitmapStep; + else tile = 8*srow*(obj.index>>5 & 31) + 16*(obj.index & 31); + + uint32 zmask = pxPriority*3u + pxLayer*7u; + uint32 flags = pxPriority*obj.priority + pxLayer*1u + pxAlpha*2u*(obj.palette+1); + bool affine = obj.renderMode & objinfo::affine; + bool size = obj.renderMode == objinfo::affineDouble; + bool hflip = obj.transform & 8; + bool vflip = obj.transform & 16; + unsigned alpha = obj.palette; + + if(blendAbove & 1<<4) flags |= pxBlendAbove; + if(blendBelow & 1<<4) flags |= pxBlendBelow; + + flags |= pxBlendForce + (2*alpha+1)*pxAlpha; + + affineparam tf = { 0x100, 0, 0, 0x100 }; + + int32 cx = 8*objw/2, ox = 0 - (cx << size), dw = 8*objw << size; + int32 cy = 8*objh/2, oy = y - (cy << size), dh = 8*objh << size; + + if(affine) { + tf = objTransform[obj.transform]; + } else { + if(hflip) ox++, tf.dx_dh *= -1; + if(vflip) oy++, tf.dy_dv *= -1; + } + + int32 fx = ox*tf.dx_dh + oy*tf.dx_dv; + int32 fy = ox*tf.dy_dh + oy*tf.dy_dv; + + int x = obj.x + 8; + for(unsigned t = 0; t < dw && x < 256+8; x++, t++) { + uint32 mx = (fx >> 8) + cx; + uint32 my = (fy >> 8) + cy; + + if(mx < 8*objw && my < 8*objh) { + unsigned taddr = tile + srow*my + 2*mx; + + uint16 data = system.vmap.obj(which, taddr>>14)[taddr]; + + if(x >= 0 && (data & 0x8000)) { + uint5 b = data>>10, g = data>>5, r = data>>0; + + if(flags < (objLayer[x] & zmask)) objLayer[x] = flags | b<<13 | g<<7 | r<<1; + } + } + fx += tf.dx_dh; + fy += tf.dy_dh; + } +} diff --git a/bsnes/nds/ppu/ppu.cpp b/bsnes/nds/ppu/ppu.cpp new file mode 100644 index 00000000..c5197b5d --- /dev/null +++ b/bsnes/nds/ppu/ppu.cpp @@ -0,0 +1,414 @@ +#include + +namespace NintendoDS { + +PPU ppu[2]; + + + +PPU::PPU() { +} + +void PPU::power() { + forceBlank = false; + + bgLargePal = false; + bg0FromGPU = false; + bgMode = 0; + bgTileBase = 0; + bgMapBase = 0; + + for(unsigned n = 0; n < 4; n++) { + bg[n].enable = false; + bg[n].mosaic = false; + bg[n].affineWrap = false; + bg[n].depth = 0; + bg[n].priority = 0; + bg[n].size = 0; + bg[n].map = 0; + bg[n].tiles = 0; + bg[n].palette = 0; + bg[n].hoffs = 0; + bg[n].voffs = 0; + bg[n].originx = 0; + bg[n].originy = 0; + bg[n].linex = 0; + bg[n].liney = 0; + bg[n].transform.dx_dh = 0; + bg[n].transform.dy_dh = 0; + bg[n].transform.dx_dv = 0; + bg[n].transform.dy_dv = 0; + } + objEnable = false; + objInHBlank = false; + objLargePal = false; + objTileMode = 0; + objTileStep = 0; + objBitmapMode = 0; + objBitmapStep = 0; + + for(unsigned n = 0; n < 128; n++) { + obj[n].kind = objinfo::none; + obj[n].renderMode = objinfo::normal; + obj[n].mosaic = false; + obj[n].depth = 0; + obj[n].size = 0; + obj[n].shape = objinfo::square; + obj[n].transform = 0; + obj[n].x = 0; + obj[n].y = 0; + obj[n].index = 0; + obj[n].priority = 0; + obj[n].palette = 0; + } + for(unsigned n = 0; n < 32; n++) { + objTransform[n].dx_dh = 0; + objTransform[n].dy_dh = 0; + objTransform[n].dx_dv = 0; + objTransform[n].dy_dv = 0; + } + + blendMode = 0; + blendAbove = 0; + blendBelow = 0; + blendAf = 0; + blendBf = 0; + blendYf = 0; + + for(unsigned n = 0; n < 2; n++) { + winX[n][0] = 0; winX[n][1] = 0xff; + winY[n][0] = 0; winY[n][1] = 0xff; + } + winArea[0] = 0; winEnable[0] = false; + winArea[1] = 0; winEnable[1] = false; + winArea[2] = 0; winEnable[2] = false; + winArea[3] = 0; +} + + +void PPU::scanline() { + if(video.line < 192) { + // Set up backdrop + for(unsigned x = 0; x < 256+16; x++) { + above[x] = pxPriority*3u + pxLayer*6u + bgPal[0]; + below[x] = pxPriority*3u + pxLayer*7u; + objLayer[x] = pxPriority*3u + pxLayer*7u; + + if(blendAbove & 1<<5) above[x] |= pxBlendAbove; // can shade backdrop + if(blendBelow & 1<<5) above[x] |= pxBlendBelow; // can blend over backdrop + } + + // Set up window buffer + bool useWindowing = winEnable[0] || winEnable[1] || winEnable[2]; + + if(useWindowing) memset(window, 0xc0+winArea[3], 256+16); // initialize with winout + else memset(window, 0x3f, 256+16); // draw everything + + for(int w = 1; w >= 0; w--) + if(winEnable[w] && winY[w][0] <= video.line && video.line <= winY[w][1] && winX[w][1] > winX[w][0]) + memset(&window[winX[w][0] + 8], 0x40+winArea[w], winX[w][1] - winX[w][0]); + + // Draw layers + if(objEnable) + renderObjs(video.line); + + renderBgs(video.line); + + + // Feed in 3D layer, if requested + if(bg[0].enable && bg0FromGPU && which == 0) { + auto *gpuOut = &gpu.output[256*video.line]; + + uint32 depth = pxPriority*bg[0].priority + pxLayer*2; + uint32 flags = pxBlendForce; + + if(blendAbove & 1<<0) flags |= pxBlendAbove; + if(blendBelow & 1<<0) flags |= pxBlendBelow; + + for(unsigned x = 0; x < 256; x++) { + if(!(window[x+8] & 1<<0)) continue; + if(gpuOut[x] < 1*pxAlpha) continue; + + if(depth < above[8+x]) { + below[8+x] = above[8+x]; + above[8+x] = depth | flags | gpuOut[x]; + } + else if(depth < below[8+x]) { + below[8+x] = depth | flags | gpuOut[x]; + } + } + } + + // Add OBJs, if enabled + if(objEnable) { + for(unsigned x = 0; x < 256; x++) { + if(!(window[x+8] & 1<<4)) continue; + + auto &objPx = objLayer[x+8]; + auto &abovePx = above[x+8]; + auto &belowPx = below[x+8]; + + if(objPx < abovePx) belowPx = abovePx, abovePx = objPx; + else if(objPx < belowPx) belowPx = objPx; + } + } + + unsigned yf = min(32, 2*blendYf); + + uint64 round = 02000200020; + uint64 shade = round; + if(blendMode == lighten) + shade += 07700770077ull*yf; + + for(unsigned x = 0; x < 256; x++) { + auto &abovePx = above[x+8]; + auto &belowPx = below[x+8]; + + unsigned af = min(32, 2*blendAf); + unsigned bf = min(32, 2*blendBf); + + bool canShade = (abovePx & pxBlendAbove); + bool canBlend = (abovePx & (pxBlendAbove|pxBlendForce)) && (belowPx & pxBlendBelow); + bool forceAlpha = (abovePx & pxBlendForce ) && (belowPx & pxBlendBelow); + unsigned mode = forceAlpha? alphaBlend : blendMode; + + if(!(mode && (window[x+8] & 1<<5))) { + output[x] = abovePx; + continue; + } + + uint64 a = (abovePx & 0777777)*01000001ull & 07700770077ull; + uint64 b = (belowPx & 0777777)*01000001ull & 07700770077ull; + + if(forceAlpha && (abovePx & 31*pxAlpha)) + af = (abovePx>>18 & 31) + 1, bf = 32-af; + + if(canBlend && mode == alphaBlend) a = (a*af + b*bf + round)/32; + else if(canShade && mode > alphaBlend) a = (a*(32 - yf) + shade)/32; + + if(uint32 oflow = a & 010001000100) + a |= oflow - (oflow>>6); + + a &= 07700770077; + output[x] = (a | a>>18) & 0777777; + } + } +} + + +#include "bg.cpp" +#include "obj.cpp" + + +uint32 PPU::readPalette(uint32 addr) { + addr &= ~3; + uint32* p = addr < 0x200? &bgPal[addr>>1 & 0xfe] : &objPal[addr>>1 & 0xfe]; + + uint5 b0 = p[0]>>13, g0 = p[0]>>7, r0 = p[0]>>1; + uint5 b1 = p[1]>>13, g1 = p[1]>>7, r1 = p[1]>>1; + + return b0<<10 | g0<<5 | r0<<0 | b1<<26 | g1<<21 | r1<<16; +} + +void PPU::writePalette(uint32 addr, uint32 size, uint32 data) { + uint32 mask = 0xffffffff; + + if(size == Byte) size = Half; + if(size == Half) addr &= ~1, mask = 0xffff << 8*(addr & 3); + if(size == Word) addr &= ~3; + + uint32* p = addr < 0x200? &bgPal[addr>>1 & 0xfe] : &objPal[addr>>1 & 0xfe]; + + uint5 b0 = data>>10, g0 = data>> 5, r0 = data>> 0; + uint5 b1 = data>>26, g1 = data>>21, r1 = data>>16; + + if(mask & 0x0000ffff) p[0] = b0<<13 | g0<<7 | r0<<1; + if(mask & 0xffff0000) p[1] = b1<<13 | g1<<7 | r1<<1; +} + +uint32 PPU::readOam(uint32 addr) { + addr &= ~3; + + objinfo& obj = this->obj[addr/8]; + affineparam& tf = this->objTransform[addr/32]; + + switch(addr & 4) { + case 0: + return obj.y<<0 | obj.renderMode<<8 | obj.kind<10 + | obj.mosaic<<12 | obj.depth<<13 | obj.size<<14 + | obj.x<<16 | obj.transform<<25 | obj.shape<<30; + + case 4: + return obj.index<<0 | obj.priority<<10 | obj.palette<<12 + | tf.m[addr>>3 & 3]; + } +} + +void PPU::writeOam(uint32 addr, uint32 size, uint32 data) { + if(size == Byte) return; + + if(size == Word) { + addr &= ~3; + writeOam(addr+0, Half, data>>0); + writeOam(addr+2, Half, data>>16); + return; + } + + objinfo& obj = this->obj[addr/8]; + affineparam& tf = this->objTransform[addr/32]; + + switch(addr & 6) { + case 0: + obj.y = data>>0; + obj.renderMode = data>>8; + obj.kind = data>>10; + obj.mosaic = data>>12; + obj.depth = data>>13; + obj.shape = data>>14; + return; + + case 2: + obj.x = data>>0; + obj.transform = data>>9; + obj.size = data>>14; + return; + + case 4: + obj.index = data>>0; + obj.priority = data>>10; + obj.palette = data>>12; + return; + + case 6: + tf.m[addr>>3 & 3] = data; + return; + } +} + + + +uint32 PPU::regControl() { + return bgMode<<0 | bg0FromGPU<<3 | forceBlank<<7 | objInHBlank<<23 + | objTileMode<<4 | objBitmapMode<<5 | objTileStep<<20 | objBitmapStep<<22 + | bg[0].enable<<8 | bg[1].enable<<9 | bg[2].enable<<10 | bg[3].enable<<11 + | objEnable<<12 | winEnable[0]<<13 | winEnable[1]<<14 | winEnable[2]<<15 + | bgTileBase<<24 | bgMapBase<<27 | bgLargePal<<30 | objLargePal<<31; +} + +void PPU::regControl(uint32 data, uint32 mask) { + if(mask & 0x000000ff) { + bgMode = data>>0; + bg0FromGPU = data>>3; + objTileMode = data>>4; + objBitmapMode = data>>5; + forceBlank = data>>7; + } + if(mask & 0x0000ff00) { + bg[0].enable = data>>8; + bg[1].enable = data>>9; + bg[2].enable = data>>10; + bg[3].enable = data>>11; + objEnable = data>>12; + winEnable[0] = data>>13; + winEnable[1] = data>>14; + winEnable[2] = data>>15; + } + if(mask & 0x00f00000) { + objTileStep = data>>20; + objBitmapStep = data>>22; + objInHBlank = data>>23; + } + if(mask & 0xff000000) { + bgTileBase = data>>24; + bgMapBase = data>>27; + bgLargePal = data>>30; + objLargePal = data>>31; + } +} + +uint32 PPU::regBg(unsigned no) { + return bg[no].priority<<0 + | bg[no].tiles<<2 | bg[no].mosaic<<6 | bg[no].depth<<7 + | bg[no].map<<8 | bg[no].affineWrap<<13 | bg[no].size<<14; +} + +void PPU::regBg(unsigned no, uint32 data, uint32 mask) { + //bg0 = 17 00 map 23, size -, tiles --, pri 0, 3D + //bg1 = f8 8b map 24, size 3, tiles 02, pri 3, 256 color + //bg2 = b0 01 map 16, size 2, tiles 00, pri 1, 16-bit affine + //bg3 = b4 0a map 20, size 2, tiles 02, pri 2, 16-bit affine + if(mask & 0x00ff) { + bg[no].priority = data>>0; + bg[no].tiles = data>>2; + bg[no].mosaic = data>>6; + bg[no].depth = data>>7; + } + if(mask & 0xff00) { + bg[no].map = data>>8; + bg[no].affineWrap = data>>13; + bg[no].size = data>>14; + } +} + +uint32 PPU::regBgOffs(unsigned no) { + return bg[no].hoffs | bg[no].voffs<<16; +} + +void PPU::regBgOffs(unsigned no, uint32 data, uint32 mask) { + bg[no].hoffs ^= (bg[no].hoffs ^ data) & mask; data >>= 16; mask >>= 16; + bg[no].voffs ^= (bg[no].voffs ^ data) & mask; +} + +void PPU::regBgAffine(unsigned no, unsigned index, uint32 data, uint32 mask) { + if(index < 2) { + bg[no].transform.m[2*index+0] ^= (bg[no].transform.m[2*index+0] ^ data) & mask; data >>= 16; mask >>= 16; + bg[no].transform.m[2*index+1] ^= (bg[no].transform.m[2*index+1] ^ data) & mask; + } + if(index == 2) { + bg[no].originx ^= (bg[no].originx ^ data) & mask; + bg[no].linex = bg[no].originx; + } + if(index == 3) { + bg[no].originy ^= (bg[no].originy ^ data) & mask; + bg[no].liney = bg[no].originy; + } +} + +void PPU::regWinDims(unsigned index, uint32 data, uint32 mask) { + auto dims = index == 0? winX : winY; + + if(mask & 0x000000ff) dims[0][1] = data>>0; + if(mask & 0x0000ff00) dims[0][0] = data>>8; + if(mask & 0x00ff0000) dims[1][1] = data>>16; + if(mask & 0xff000000) dims[1][0] = data>>24; +} + +uint32 PPU::regWinArea() { + return winArea[0] | winArea[1]<<8 | winArea[3]<<16 | winArea[2]<<24; +} + +void PPU::regWinArea(uint32 data, uint32 mask) { + if(mask & 0x0000003f) winArea[0] = data>>0 & 0x3f; + if(mask & 0x00003f00) winArea[1] = data>>8 & 0x3f; + if(mask & 0x003f0000) winArea[3] = data>>16 & 0x3f; + if(mask & 0x3f000000) winArea[2] = data>>24 & 0x3f; +} + +uint32 PPU::regBlend() { + return blendAbove<<0 | blendMode<<6 | blendBelow<<8; +} + +void PPU::regBlend(unsigned index, uint32 data, uint32 mask) { + uint64 maskl = uint64(mask) << 32*index; + + if(maskl & 0x000000003full) blendAbove = data>>0; + if(maskl & 0x00000000c0ull) blendMode = data>>6; + if(maskl & 0x0000003f00ull) blendBelow = data>>8; + if(maskl & 0x00001f0000ull) blendAf = data>>16; + if(maskl & 0x001f000000ull) blendBf = data>>24; + if(maskl & 0x1f00000000ull) blendYf = data>>0; +} + + + +} \ No newline at end of file diff --git a/bsnes/nds/ppu/ppu.hpp b/bsnes/nds/ppu/ppu.hpp new file mode 100644 index 00000000..22049f2b --- /dev/null +++ b/bsnes/nds/ppu/ppu.hpp @@ -0,0 +1,148 @@ + +struct PPU { + PPU(); + + void power(); + void scanline(); + + struct objinfo; + + void renderBgs(unsigned y); + void renderTiledBg(unsigned no, unsigned mapW, unsigned mapH, unsigned y); + void renderAffineBg(unsigned no, unsigned mapDepth, unsigned mapW, unsigned mapH, unsigned y); + void renderBitmapBg(unsigned no, unsigned mapDepth, unsigned mapW, unsigned mapH, unsigned y); + + void renderObjs(unsigned y); + void renderTiledObj (objinfo& obj, unsigned objw, unsigned objh, unsigned y); + void renderBitmapObj(objinfo& obj, unsigned objw, unsigned objh, unsigned y); + + uint32 readPalette(uint32 addr); + void writePalette(uint32 addr, uint32 size, uint32 data); + + uint32 readOam(uint32 addr); + void writeOam(uint32 addr, uint32 size, uint32 data); + + uint32 regControl(); + void regControl(uint32 data, uint32 mask); + + uint32 regBg(unsigned no); + void regBg(unsigned no, uint32 data, uint32 mask); + + uint32 regBgOffs(unsigned no); + void regBgOffs(unsigned no, uint32 data, uint32 mask); + + void regBgAffine(unsigned no, unsigned index, uint32 data, uint32 mask); + + void regWinDims(unsigned index, uint32 data, uint32 mask); + + uint32 regWinArea(); + void regWinArea(uint32 data, uint32 mask); + + uint32 regBlend(); + void regBlend(unsigned index, uint32 data, uint32 mask); + + // PPU #0: PPU #1: + // Has access to VRAM banks 0..6 More limited features + // BG0 can source 3D GPU output Has access to VRAM banks 2,3,7,8 + // Can use frame- and render-buffers Max 128K BG, 128K OBJ + // Max 512K BG, 256K OBJ + int which; + uint1 powered; + + // Internal pixel format: pplllMBAF aaaaa bbbbbb gggggg rrrrrr + enum { + pxPriority = 1<<30, // p - from BG control + pxLayer = 1<<27, // l - 1: OBJ, 2..5:BG, 6:backdrop + pxMosaic = 1<<26, // M + pxBlendBelow = 1<<25, // B + pxBlendAbove = 1<<24, // A + pxBlendForce = 1<<23, // F - for 3D/OBJ pixel + pxAlpha = 1<<18, // a - alpha (0=solid) + }; + + uint32 output[256]; + + uint32 above[256 + 16]; + uint32 below[256 + 16]; + uint32 objLayer[256 + 16]; + + uint32 bgPal[256]; + uint32 objPal[256]; + + union affineparam { + struct { + int16 dx_dh, dx_dv; // A, B + int16 dy_dh, dy_dv; // C, D + }; + int16 m[4]; + }; + + struct bginfo { + uint1 enable; + uint1 mosaic, depth; + uint1 affineWrap; + uint2 priority; + uint2 size; + uint5 map; // 2K offset for maps / 16K for bitmaps + uint4 tiles; // 16K offset for tiles + uint2 palette; // 8K offset for large palette mode + + uint9 hoffs, voffs; // Tiled scrolling + int32 originx, originy; // Affine settings + int32 linex, liney; + affineparam transform; + }; + + struct objinfo { + uint2 kind; enum { none=0, blend=1, window=2, bitmap=3 }; + uint2 renderMode; enum { normal=0, affine=1, hidden=2, affineDouble=3 }; + uint1 mosaic; + uint1 depth; + uint2 size; + uint2 shape; enum { square=0, wide=1, tall=2 }; + uint5 transform; enum { hflip=8, vflip=16 }; + int9 x; + uint8 y; + uint10 index; + uint2 priority; + uint4 palette; // subpalette for tiled; alpha for bitmap sprites + }; + + uint1 forceBlank; + + uint1 bgLargePal; // 256-color BGs use system.vmap.bgpal + uint1 bg0FromGPU; // Display 3D rendering on BG0 + uint3 bgMode; // Determines affine vs. tiled layers + uint3 bgTileBase; // 64K starting base for tiles + uint3 bgMapBase; // 64K starting base for maps + uint4 bgMosaicX; + uint4 bgMosaicY; + bginfo bg[4]; + + uint1 objEnable; + uint1 objInHBlank; + uint1 objLargePal; // 256-color OBJs use system.vmap.objpal + uint1 objTileMode; // 0 = 256x256 px sprite sheet, 1 = linear + uint2 objBitmapMode; // 0 = 128x256, 1 = 256x256, 2..3 = linear + uint2 objTileStep; // tile index << in linear mode + uint1 objBitmapStep; // + uint4 objMosaicX; + uint4 objMosaicY; + objinfo obj[128]; + + affineparam objTransform[32]; + + uint1 winEnable[3]; // [win0, win1, winobj, winout] + uint8 winArea[4]; // BLD, OBJ, BG3..BG0 + uint8 winX[2][2]; // + uint8 winY[2][2]; // not uint9 - Nintendo's oversight + uint8 window[256+16]; // window no.<<6 | area + + uint2 blendMode; enum { alphaBlend=1, lighten=2, darken=3 }; + uint6 blendAbove; // BG0..BG3, OBJ, lignten/darken BD + uint6 blendBelow; // BG0..BG3, OBJ, blend over BD + uint5 blendAf, blendBf; // alphaBlend coefficients + uint5 blendYf; // lighten/darken coefficient +}; + +extern PPU ppu[2]; diff --git a/bsnes/nds/slot1/slot1.cpp b/bsnes/nds/slot1/slot1.cpp new file mode 100644 index 00000000..f30232d9 --- /dev/null +++ b/bsnes/nds/slot1/slot1.cpp @@ -0,0 +1,244 @@ +#include + +namespace NintendoDS { + +Slot1 slot1; + + +Slot1::Slot1() { + card = nullptr; +} + +void Slot1::power() { + if(card) { + card->power(); + if(card->spi) + card->spi->power(); + } + enable = true; + + decryptLatency = 0; + responseLatency = 0; + xorData = 0; + xorCmds = 0; + dataReady = 0; + blockSize = 0; + clock = 0; + secureMode = 0; + transferPending = 0; + transferIrq = 0; + transferLength = 0; + + command = 0; + lfsr[0] = 0; + lfsr[1] = 0; + + spi.data = 0; + spi.baud = 0; + spi.hold = 0; + spi.busy = 0; + spi.enable = 0; +} + +void Slot1::load(GameCard* card) { + this->card = card; + if(card->spi) + card->spi->power(); +} + +GameCard* Slot1::unload() { + //if(card && card->spi) + // card->spi->select(false); + + auto r = card; + card = nullptr; + return r; +} + + +void Slot1::startRomTransfer() { + transferPending = true; + transferLength = 0; + + if(blockSize == 7) transferLength = 4; + else if(blockSize) transferLength = 512 << (blockSize-1); + + if(transferLength) dataReady = true; + else transferPending = false; + + if(card) card->command(command); + + // Hack for now, until we implement timing. Should test whether the ARM9 + // halts during this entire DMA - one complete word transfers every 40 or + // 64 clocks at 66MHz. + CPUCore *arm = arm9.slot1access? (CPUCore*)&arm9 : (CPUCore*)&arm7; + //while(transferLength > 0 && arm->dmaTrigger(0xf, 5)) /**/; + int ch = -1; + for(unsigned n = 0; n < 4; n++) + if(arm->dma[n].enable && arm->dma[n].trigger == 5) + ch = n; + + while(ch >= 0 && transferLength > 0) + arm->dmaTransfer(ch); +} + +uint8 Slot1::readRom() { + uint8 data = 0xff; + + if(transferLength) { + // Empty slot simply returns 0xff + if(card) data = card->read(); + + if(!--transferLength) { + dataReady = false; + transferPending = false; + + if(transferIrq) { + if(arm9.slot1access == 0) arm7.interrupt.flags |= CPUCore::irqCardDone; + if(arm9.slot1access == 1) arm9.interrupt.flags |= CPUCore::irqCardDone; + } + } + } + return data; +} + +uint8 Slot1::spiTransfer(uint8 data) { + if(!card || !card->spi) + return 0xff; + + auto device = card->spi; + device->select(true); + uint8 r = device->transfer(data); + device->select(spi.hold); + return r; +} + + +GameCard::~GameCard() { + delete spi; +} + +GameCard::GameCard(uint32 id) { + rom.size = 0x10000; + rom.data = new uint8[rom.size]; + memset(rom.data, 0xff, rom.size); + + size = bit::round(rom.size); + chipId = id; + spi = nullptr; +} + +GameCard::GameCard(const stream& memory, uint32 esize, uint32 id) { + rom.size = esize; + rom.data = new uint8[rom.size]; + memset(rom.data, 0xff, rom.size); + memory.read(rom.data, min(memory.size(), rom.size)); + + size = bit::round(rom.size); + sha256 = nall::sha256(rom.data, rom.size); + chipId = id; + spi = nullptr; +} + +void GameCard::power() { + state = idle; +} + +void GameCard::command(uint64 command) { + if((command>>56) == 0xb7) { + state = readData; + offset = command>>24 & 0x00000fff; + block = command>>24 & 0xfffff000; + block &= size-1; + + // Once initialized, forbid reading the header and startup code. + if(block < 0x8000) block += 0x8000; + } + if((command>>56) == 0xb8) { + state = readId; + offset = 0; + } +} + +uint8 GameCard::read() { + uint8 r = 0xff; + + if(state == readData) { + // We remain in this state indefinitely, until the next command. + // However, reading from most (?) game cards wraps at 4K intervals. + uint32 addr = (block + offset++) & size-1; + offset &= 0xfff; + + // Cards come in 2^n ROM sizes, however many images have the empty space + // trimmed off. Homebrew images aren't even padded out! Rather than waste + // memory, just check for this and return $ff. + if(addr < rom.size) + r = rom.data[addr]; + } + + if(state == readId) { + // Need to ensure the matching ID is in RAM or games won't run + // (where does the firmware put it?) + r = 0;/**/chipId >> 8*offset++; + offset &= 3; + } + return r; +} + + + +void IRPort::power() { + bypass = false; + command = 0; + if(slave) + slave->power(); +} + +void IRPort::select(bool state) { + if(bypass) { + slave->select(state); + } + if(state == false) { + bypass = false; + command = 0; + } +} + +uint8 IRPort::transfer(uint8 data) { + if(bypass) { + // Pass transfers through to flash memory + if(slave) return slave->transfer(data); + else return 0xff; + } + + if(command == 0x00) { + command = data; + + // Engage passthrough mode - allows access to save data. + if(command == 0x00) { + bypass = true; + return 0xff; + } + + if(command == 0x01) { + // Receive? HG/SS expect an 8-bit packet size, + // then 0..185 bytes, all XORed with $aa. + return 0x00; + } + + if(command == 0x02) { + // Write a packet, maybe to transmit buffer + return 0xff; + } + + if(command == 0x08) { + // ID of some kind? Is it even a valid command? + // Returns $aa after powerup - haven't tested the Pokewalker with it. + // Pokemon HG/SS frequently check this, even when not communicating. + return 0xaa; + } + } + return 0xff; +} + +} diff --git a/bsnes/nds/slot1/slot1.hpp b/bsnes/nds/slot1/slot1.hpp new file mode 100644 index 00000000..05219ef6 --- /dev/null +++ b/bsnes/nds/slot1/slot1.hpp @@ -0,0 +1,113 @@ + +struct GameCard; +struct SPIDevice; + +// Pins 1-17: GND, Clock, -, /ROM, /RESET, /SPI, /IRQ, VCC, D0-D7, GND +// +// This is a hybrid serial-parallel bus, one byte transferred each clock. +// Both the cards and the slot support XOR obfuscation using a 39-bit LFSR, +// and some commands are further encrypted via a Blowfish variant. +// +// Transfer rates are 33MHz /5 or /8, which is 4-6MB/sec, and there's a +// 32-bit buffer making it possible to DMA straight to VRAM. For perspective, +// 6MB/s is enough to stream 256x192x16bpp video + audio at 60fps. + +struct Slot1 { + Slot1(); + void power(); + void load(GameCard* card); + GameCard* unload(); + + void startRomTransfer(); + uint8 readRom(); + uint8 spiTransfer(uint8 data); + + GameCard *card; + + uint1 enable; + + // ROM interface + uint1 clock; // 33MHz / {5, 8} + uint13 decryptLatency; // clocks to wait for card to decrypt command + uint6 responseLatency; // clocks to wait for response (data buffering?) + uint2 xorData; // XOR data received (2 bits?) + uint1 xorCmds; // XOR commands sent + uint1 dataReady; // 32 bits buffered and ready in read port + uint3 blockSize; // {0, 512 bytes (usual), 1K-16K, 32 bits} + uint1 secureMode; // ? + uint1 transferIrq; // generate IRQ at end of block + uint1 transferPending; // still more bytes to transfer? + uint32 transferLength; // # bytes remaining + + uint64 command; // latch holding 8 command bytes for next transfer + uint64 lfsr[2]; // registers used to obfuscate communication + + // Serial interface for EEPROM, flash, and peripheral access. + // Each transfer writes and reads 8 bits, one bit per clock. + // Pins D6/D7 do double duty as data in/out respectively. + struct SPI { + uint8 data; // read from last transfer + uint2 baud; // 4MHz >> n + uint1 enable, busy, hold; + } spi; +}; + +struct GameCard { + virtual ~GameCard(); + GameCard(uint32 id); + GameCard(const stream& memory, uint32 size, uint32 id); + + virtual void power(); + virtual void command(uint64 command); + virtual uint8 read(); + + int state; enum { idle, readData, readId }; + uint32 block; // 4K block for reading + uint32 offset; // byte offset + uint32 size; // power of 2 rom size + uint64 lfsr[2]; // for obfuscation + uint32 chipId; + string sha256; + + StaticMemory rom; + SPIDevice *spi; +}; + +struct IRPort : SPIDevice { + IRPort() : slave(nullptr) { } + IRPort(SPIDevice *slave) : slave(slave) { } + + void power(); + void select(bool state); + uint8 transfer(uint8 data); + + SPIDevice *slave; + bool bypass; + uint8 command; +}; + +struct S1EEPROM : SPIDevice, StaticMemory { + void select(bool state); + uint8 transfer(uint8 data); + + int state; enum { idle, params, dataIo }; + uint8 command; enum { + cmdWriteDisable, cmdWriteEnable, // 0x04, 0x06 + cmdWriteStatus, cmdReadStatus, // 0x01, 0x05 + cmdWrite, cmdRead, // 0x02, 0x03 + cmdReadID, // 0x9f + }; + uint8 numArgs; + uint32 offset; + + // Status register + uint1 busy; + uint1 writeEnable; + uint2 writeProtect; + uint1 statusLock; + + uint1 unlockable; // /W pin, presumably enabled on game cards +}; + + +extern Slot1 slot1; diff --git a/bsnes/nds/slot2/slot2.cpp b/bsnes/nds/slot2/slot2.cpp new file mode 100644 index 00000000..e69de29b diff --git a/bsnes/nds/slot2/slot2.hpp b/bsnes/nds/slot2/slot2.hpp new file mode 100644 index 00000000..e69de29b diff --git a/bsnes/nds/system/clock.cpp b/bsnes/nds/system/clock.cpp new file mode 100644 index 00000000..3ddd7376 --- /dev/null +++ b/bsnes/nds/system/clock.cpp @@ -0,0 +1,239 @@ + +Clock::~Clock() { } + +Clock::Clock() { + stoppedSec = 0; + stoppedUSec = 0; +} + +void Clock::reset() { + status1 = 0; year = 0; hour = 0; + status2 = 0; month = 1; minute = 0; + adjust = 0; day = 1; second = 0; + userByte = 0; weekday = 0; + + for(int i = 0; i < 2; i++) + for(int j = 0; j < 3; j++) + alarm[i].setting[j] = 0; +} + +void Clock::power() { + secondsTickPending = hold = false; + intr[0] = intr[1] = lag = 0; + lastClk = lastCs = output = false; + command = buffer = nbits = dataOut = 0; + + // The clock is 32768 Hz but we need twice that, because serial + // interrupts are edge sensitive. + event.action = [&]() { + tick(); + arm7.event.queue.add(2*33513982/(2*32768), event); + }; + arm7.event.queue.add(2*33513982/(2*32768), event); +} + +uint4 Clock::io(uint4 pins) { + uint1 dataIn = pins>>0; + uint1 clk = pins>>1; + uint1 cs = pins>>2; + + if(cs != lastCs && !(lastCs = cs)) { + command = nbits = 0; + output = false; + return 0xf; + } + // Wait for falling CLK edge with CS high.. + if(clk != lastClk && !(lastClk = clk)) { + // Rotate data through the buffer + dataOut = buffer; + buffer = dataIn<<7 | buffer>>1; + + if(++nbits == 0) { + // Have we got a full byte to act on? + + // Accept a new command. They're MSB first, unlike data: + if(!command && (buffer & 0x0f) == 6) { // 0110 + command = buffer & 0x7f; // ccc + output = buffer & 0x80; // D + index = 0; + + // Prevent the time changing while read + if(command == 0x26 || command == 0x66) + hold = true; + + if(output == false) return 0xf; + else /*fall through and latch output byte for reading*/; + } + if(command == 0x06) field(status1, resetBit|hourMode); + if(command == 0x46) field(status2, int1Mode|int2Mode|testMode); + if(command == 0x26) dateTime(); + if(command == 0x66) dateTime(); + if(command == 0x16) alarmTime(0); + if(command == 0x56) alarmTime(1); + if(command == 0x36) field(adjust, 0xff); + if(command == 0x76) field(userByte, 0xff); + } + } + return output? dataOut | 0xe : 0xf; +} + + + +void Clock::field(uint8& src, uint8 mask) { + if(command == 0x06 && output == 0 && (buffer & resetBit)) { + reset(); buffer &= ~resetBit; + } + if(output) buffer = src; + else src ^= (src ^ buffer) & mask; +} + +void Clock::dateTime() { + if(index >= 7) return; + if(command == 0x66) // start from time field + index = max(4, index); + + bool fixHour = !(status1 & hourMode) && index == 4; + + if(output) { + buffer = time[index++]; + if(fixHour && buffer >= 0x12) + buffer += 0x40 - 0x12; // Convert back to 12-hour + AM/PM + return; + } + time[index] = buffer; // Should correct these properly.. + if(fixHour && (buffer & 0x40)) + time[index] += 0x12 - 0x40; // Convert from 12-hour mode + index++; +} + +void Clock::alarmTime(unsigned no) { + if(index >= 3) return; + if(output) buffer = alarm[no].setting[index++]; + else alarm[no].setting[index++] = buffer; +} + + + +bool Clock::incBCD(uint8& val, uint8 first, uint8 last) { + val++; + if((val & 0x0f) == 0x0a) val += 0x06; + if((val & 0xf0) == 0xa0) val += 0x60; + if(val > last) val = first; + return val == first; // carry out +} + +void Clock::tick() { + bool previously = intr[0] | intr[1]; + + if(++counter == 0) + secondsTickPending = true; + + // Ticks can be held for up to 500 ms while reading the time. + if(secondsTickPending && (hold == false || counter >= 2*16384)) { + lag = counter; + tickSecond(); + } + + switch(status2 & int2Mode /*0..1*/) { + case 0: intr[1] = 0; break; + default: break; // Alarm 2 - checked in tickSecond + } + + switch(status2 & int1Mode /*0..15*/) { + case 0: intr[0] = 0; break; + case 4: break; // Alarm 1 - checked in tickSecond + + case 1: /**/; + case 5: // Selectable frequency - often used as seconds interrupt. + intr[0] = 0; // /IRQ output is the AND of the selected divisors. + for(unsigned divisor = 0; divisor <= 4; divisor++) // 1..16 Hz + intr[0] |= (~counter >> 15-divisor) & (alarm[0].minute >> divisor) & 1; + break; + + case 2: /**/; // Start-of-minute interrupts + case 6: intr[0] |= !second && counter-lag < 2*4u; break; // latched + case 3: intr[0] = second < 0x30; break; // 30 sec duty + case 7: intr[0] = counter-lag < lag+2*128u; break; // 128 ticks duty + + default: intr[0] = !(counter & 1<<0); break; // 32KHz clock + } + + if(intr[0]) status1 |= int1Flag; + if(intr[1]) status1 |= int2Flag; + + bool interrupt = intr[0] | intr[1]; + + if(arm7.sio.irq && interrupt && previously == false) { + //arm7.raiseIrq(CPUCore::irqClock); + arm7.interrupt.flags |= CPUCore::irqClock; + } +} + +void Clock::tickSecond() { + secondsTickPending = false; + + if( incBCD(second, 0, 0x59) + && incBCD(minute, 0, 0x59) + && incBCD(hour, 0, 0x23)) + tickDay(); + + // Check alarms - not sure how this is supposed to work yet. + // The datasheet implies this is checked each minute, something like: + // d:hh:mm weekly d:**:mm hourly for one day a week? + // *:hh:mm daily d:**:** every minute for one day a week? + // *:**:mm hourly? d:hh:** every minute for one hour on one day? + // *:**:** every minute? *:hh:** every minute for one hour a day + if(second == 0x00) { + bool enable[2] = { + (status2 & int1Mode) == 4, // Alarm 1 + (status2 & int2Mode) != 0, // Alarm 2 + }; + // Triggered at start of minute; cleared by disabling alarm + for(unsigned i = 0; i < 2; i++) + if(enable[i] + && (weekday == (alarm[i].weekday & 0x07) || alarm[i].weekday < 0x80) + && (hour == (alarm[i].hour & 0x1f) || alarm[i].hour < 0x80) + && (minute == (alarm[i].minute & 0x3f) || alarm[i].minute < 0x80)) + intr[i] = 1; + + } +} + +void Clock::tickDay() { + if(++weekday == 7) weekday = 0; + + unsigned y = 10*(year>>4) + (year & 15); + unsigned daysIn[32] = { 0, // (invalid) + 0x31,0x28+!(y % 4), // Jan..Feb + 0x31,0x30,0x31,0x30,0x31, // Mar..Jul + 0x31,0x30, 0,0,0,0,0,0, // Aug..Sep (+ invalid months) + 0x31,0x30,0x31 // Oct..Dec + }; + incBCD(day, 1, daysIn[month & 31]) + && incBCD(month, 1, 0x12) + && incBCD(year, 0, 0x99); +} + + +void Clock::thaw(int64 curSec, int64 curUSec) { + // Calculate time elapsed while the emulation wasn't running.. + // Then advance RTC to make up for it. + int64 secs = curSec - stoppedSec; + int64 usecs = curUSec - stoppedUSec; + if(usecs < 0) secs -= 1, usecs += 1000000; + + int32 ticks = counter + usecs * 32768/1000000; + counter = ticks; + if(ticks >= 32768) secs += 1; + + while(secs > 86400) { secs -= 86400; tickDay(); } + while(secs > 0) { secs -= 1; tickSecond(); } + + stoppedSec = curSec; + stoppedUSec = curUSec; +} + +void Clock::freeze(int64 curSec, int64 curUSec) { + stoppedSec = curSec; + stoppedUSec = curUSec; +} diff --git a/bsnes/nds/system/eventqueue.hpp b/bsnes/nds/system/eventqueue.hpp new file mode 100644 index 00000000..6ae71226 --- /dev/null +++ b/bsnes/nds/system/eventqueue.hpp @@ -0,0 +1,120 @@ + +template struct Event_of { + uint32 time; + uint32 node; + T action; + + Event_of() : time(0), node(0) {} + Event_of(T action) : time(0), node(0), action(action) {} + inline bool operator<(const Event_of& rhs) const { return time - rhs.time >= 0x80000000u; } + inline bool operator<(uint32 rhs) const { return time - rhs >= 0x80000000u; } +}; + +template struct EventQueue_of { + typedef Event_of Elem; + + uint32 time; + + EventQueue_of(uint32 capacity) : size(0), time(0) { + //items.reserve(capacity+1); // to simplify math, items[0] is unused + for(unsigned n = 0; n < capacity+1; n++) + items[n] = nullptr; + } + + void reset() { + clear(); + time = 0; + } + void clear() { + for(unsigned n = 1; n <= size; n++) { + items[n]->node = 0; + items[n] = nullptr; + } + size = 0; + } + bool valid(uint32 n = 1) { + return (2*n+0 > size || *(items[n]) < items[2*n+0]->time+1 && valid(2*n+0)) + && (2*n+1 > size || *(items[n]) < items[2*n+1]->time+1 && valid(2*n+1)); + } + void add(uint32 dt, Elem& e) { + if(e.node) { + remove(e); + return add(dt, e); + } + uint32 old = e.time; + e.time = time + dt; + e.node = ++size; + bubble(e); + if(valid() == false) asm volatile("\n\t int $3"); + } + void remove(Elem& e) { + if(e.node == 0) return; + + items[e.node] = items[size]; + items[e.node]->node = e.node; + items[size--] = nullptr; + + if(size > 1 && e.node <= size) { + Elem& m = *(items[e.node]); + + if(m < e) { + // This can happen if removing something besides the min element. + bubble(m); + if(valid() == false) asm volatile("\n\t int $3"); + } + else { + while(2*m.node <= size) { + uint32 l = 2*m.node; + uint32 r = 2*m.node + (l < size); + uint32 c = *(items[r]) < *(items[l])? r : l; + + if(!(*(items[c]) < m)) break; + + items[m.node] = items[c]; + items[m.node]->node = m.node; + m.node = c; + } + items[m.node] = &m; + if(valid() == false) asm volatile("\n\t int $3"); + } + } + e.node = 0; + } + + inline void step(uint32 ticks) { + ticks += time; // relative -> absolute time + time = ticks; // default case for early out + + // Caution! We're running under the assumption our queue is never empty. + // Fortunately, due to audio/video events, that's true in dasShiny. + // Gives around 16% speedup in some cases. + if(!(*(items[1]) < ticks)) return; // early out, nothing to do + + auto &next = items[1]; + do { + Elem& e = *next; + time = e.time; // update the time so add() + remove(e); // works during the callback. + e.action(); + } while(/*size && */*next < ticks); + + if(time - ticks >= 0x80000000u) + time = ticks; + } + +//private: + //linear_vector items; + Elem* items[64]; + uint32 size; + + void bubble(Elem& e) { + while(1 < e.node && e < *(items[e.node/2])) { + items[e.node] = items[e.node/2]; + items[e.node]->node = e.node; + e.node /= 2; + } + items[e.node] = &e; + } + + EventQueue_of(); +}; diff --git a/bsnes/nds/system/powermgr.cpp b/bsnes/nds/system/powermgr.cpp new file mode 100644 index 00000000..cfb56820 --- /dev/null +++ b/bsnes/nds/system/powermgr.cpp @@ -0,0 +1,14 @@ + +PowerMgr::~PowerMgr() { } + +void PowerMgr::power() { + +} + +void PowerMgr::select(bool state) { + +} + +uint8 PowerMgr::transfer(uint8 data) { + return 0; +} diff --git a/bsnes/nds/system/system.cpp b/bsnes/nds/system/system.cpp new file mode 100644 index 00000000..cc2b6c7c --- /dev/null +++ b/bsnes/nds/system/system.cpp @@ -0,0 +1,537 @@ +#if !defined(_WIN32) + #include + #include +#else + // Suppress mingw's timeval which uses 32-bit longs + #define _TIMEVAL_DEFINED + #include + #include + #include + + struct timeval { + int64_t tv_sec, tv_usec; + }; + #define timegm(tm) _mkgmtime64(tm) + #define gmtime(tv) _gmtime64(tv) + #define gettimeofday(tv,tz) gettimeofday64(tv,tz) + + int gettimeofday64(struct timeval *tv, struct timezone *tz) { + FILETIME ft; + GetSystemTimeAsFileTime(&ft); // UTC in 100ns units + + // UNIX epoch: Jan 1 1970 + // Windows epoch: Jan 1 1601 + // + // 1970 - 1601 = 369 years = 11636784000 sec + // 89 leap years => +89 days = +7689600 sec + int64_t diff = 11644473600LL * 10000000LL; + int64_t ns = ft.dwLowDateTime + ft.dwHighDateTime * (1LL<<32) - diff; + + tv->tv_sec = ns / 10000000; + tv->tv_usec = ns % 10000000 / 10; + } +#endif + + +namespace NintendoDS { + +System system; + + +SPIDevice::~SPIDevice() { } + + +VRAMMapping::VRAMMapping() { + data = nullptr; size = 0; + dirtyBits = nullptr; +} +VRAMMapping::VRAMMapping(HalfMemory& target, uint8 *dirtyBits, unsigned pageno) + : dirtyBits(dirtyBits + pageno*256/0x4000) +{ + data = target.data + 0x4000/2*pageno; size = 0; +} +VRAMMapping::~VRAMMapping() { + data = nullptr; size = 0; + dirtyBits = nullptr; +} + +uint16& VRAMMapping::operator[](uint32 addr) { + return data? data[addr>>1 & 0x1fff] + : system.unmappedVram[addr>>1 & 0x1fff]; +} + +uint32 VRAMMapping::read(uint32 addr, uint32 size) { + if(!data) return 0; + return HalfMemory::read(addr & 0x3fff, size); +} +void VRAMMapping::write(uint32 addr, uint32 size, uint32 word) { + if(!data) return; HalfMemory::write(addr & 0x3fff, size, word); + if(!dirtyBits) return; dirtyBits[(addr & 0x3fff)/256] = 0xff; +} +bool VRAMMapping::dirty(uint32 addr) { + return dirtyBits && dirtyBits[(addr & 0x3fff)/256]; +} + + +System::System() { + firmware.data = new uint8 [(firmware.size = 0x080000)/1](); + + ewram.data = new uint16[(ewram.size = 0x400000)/2]; + iwram.data = new uint32[(iwram.size = 0x010000)/4]; + swram[0].data = new uint32[(swram[0].size = 0x004000)/4]; + swram[1].data = new uint32[(swram[1].size = 0x004000)/4]; + + vram[0].data = new uint16[(vram[0].size = 0x020000)/2]; + vram[1].data = new uint16[(vram[1].size = 0x020000)/2]; + vram[2].data = new uint16[(vram[2].size = 0x020000)/2]; + vram[3].data = new uint16[(vram[3].size = 0x020000)/2]; + vram[4].data = new uint16[(vram[4].size = 0x010000)/2]; + vram[5].data = new uint16[(vram[5].size = 0x004000)/2]; + vram[6].data = new uint16[(vram[6].size = 0x004000)/2]; + vram[7].data = new uint16[(vram[7].size = 0x008000)/2]; + vram[8].data = new uint16[(vram[8].size = 0x004000)/2]; + + wxram.data = new uint16[(wxram.size = 0x002000)/2]; + + memset(firmware.data, 0, firmware.size); + + callerThread = nullptr; + activeThread = nullptr; + running = false; +} + +void System::mapVram(VRAMMapping* loc, uint8 *dirtyBits, unsigned npages, HalfMemory& bank) { + for(unsigned offset = 0; offset < npages; offset++) + loc[offset] = VRAMMapping{ bank, dirtyBits, offset % (bank.size/0x4000) }; +} + +void System::clearVmap() { + for(unsigned n = 0; n < 8; n++) { + for(auto &m : vmap.arm9[n]) m = VRAMMapping{}; + } + for(auto &m : vmap.arm7) m = VRAMMapping{}; + for(auto &m : vmap.tex) m = VRAMMapping{}; + for(auto &m : vmap.texpal) m = VRAMMapping{}; + for(auto &m : vmap.bgpal[0]) m = VRAMMapping{}; + for(auto &m : vmap.objpal[0]) m = VRAMMapping{}; + for(auto &m : vmap.bgpal[1]) m = VRAMMapping{}; + for(auto &m : vmap.objpal[1]) m = VRAMMapping{}; +} + +void System::updateVmap() { + static const uint32 offsets[] = { + 0x00000, 0x20000, 0x40000, 0x60000, 0x80000, 0x90000, 0x94000, 0x98000, 0xa0000 + }; + static const uint32 altOffsets[] = { + 0x00000, 0x04000, 0x10000, 0x14000 + }; + + clearVmap(); + gpu.texCache.reset(); + + auto bank = vmap.regs; + + for(unsigned n = 0; n < 7; n++) { + if(!bank[n].enable) continue; + + unsigned offset = offsets[n] >> 14; + unsigned npages = vram[n].size >> 14; + + int sel = bank[n].bus; + + // Restrict MST to valid options (some are mirrored) + if(n < 2 || n < 4 && sel > 4 || sel > 5) sel &= 3; + + if(sel == VRAMConfig::display) + mapVram(&vmap.arm9[4][offset], &vmap.dirty[offsets[n]/256], npages, vram[n]); + } + + // Banks 0-3, all are 128K, mapped at increments of the same size. + for(unsigned n = 0; n < 4; n++) { + if(!bank[n].enable) continue; + + unsigned offset = offsets[bank[n].offset] >> 14; + unsigned npages = vram[n].size >> 14; + + uint8* dirty = &vmap.dirty[offsets[n]/256]; + uint8* dirtyEnd = &vmap.dirty[offsets[n+1]/256]; + + VRAMMapping *bus = nullptr; + int sel = bank[n].bus; + if(n < 2 || sel > 4) sel &= 3; + + if( sel == VRAMConfig::bg0) bus = &vmap.bg(0, offset); + if(n < 2 && sel == VRAMConfig::obj0) bus = &vmap.obj(0, offset); + if(n >= 2 && sel == VRAMConfig::arm7) bus = &vmap.arm7[offset]; + if(n == 2 && sel == VRAMConfig::ppu1) bus = &vmap.bg(1, 0); + if(n == 3 && sel == VRAMConfig::ppu1) bus = &vmap.obj(1, 0); + + if(sel == VRAMConfig::tex) { + bus = &vmap.tex[offset]; + + // Discard dirty textures, then mark the locked pages clean. Lines + // 191..213 are available for texture updates; games wishing to do so + // will perform at least one {unlock, DMA, lock} cycle in that time. + gpu.texCache.flushDirty(n); + memset(dirty, 0, dirtyEnd-dirty); + } + if(bus) mapVram(bus, dirty, npages, vram[n]); + } + + // Banks 4-6 are 32K + 16K + 16K and carry over from the GBA. + // They always map into the first 128K of address space. + for(unsigned n = 4; n < 7; n++) { + if(!bank[n].enable) continue; + + uint8* dirty = &vmap.dirty[offsets[n]/256]; + uint8* dirtyEnd = &vmap.dirty[offsets[n+1]/256]; + + unsigned offset = n > 4? altOffsets[bank[n].offset] >> 14 : 0; + unsigned npages = vram[n].size >> 14; + + VRAMMapping *bus = nullptr; + int sel = bank[n].bus; + if(sel > 5) sel &= 3; + + if(sel == VRAMConfig::bg0) bus = &vmap.bg(0, offset); + if(sel == VRAMConfig::obj0) bus = &vmap.obj(0, offset); + if(sel == VRAMConfig::bgpal0) bus = &vmap.bgpal[0][offset]; + if(sel == VRAMConfig::objpal0) bus = &vmap.objpal[0][offset]; + + if(sel == VRAMConfig::texpal) { + bus = &vmap.texpal[offset]; + + // The current implementation caches textures in ABGR format, + // so we need to check for dirty palettes, too. + gpu.texCache.flushDirty(n); + memset(dirty, 0, dirtyEnd-dirty); + } + + if(bus) { + // Banks 5 and 6 (x) have offset 0 [x x ..............] + // mirroring that allows them to 1 [ x x ..128K banks..] + // map adjacent to larger banks. 2 [ x x ..............] + // Bank 4 (f) is fixed: 3 [ffff x x..............] + mapVram(bus + 0, dirty, npages, vram[n]); + if(n > 4) mapVram(bus + 2, dirty, npages, vram[n]); + } + } + + // These two banks are only used with PPU1. + for(unsigned n = 8; n < 10; n++) { + if(!bank[n].enable) continue; + + uint8* dirty = &vmap.dirty[offsets[n-1]/256]; + int sel = bank[n].bus & 3; + + if(sel == VRAMConfig::bg1) { + // These map in an odd sequence [hh hh ] + // where the Is mirror in pairs: [ ii ii] + mapVram(&vmap.bg(1, n==9? 2 : 0), dirty, 2, vram[n-1]); + mapVram(&vmap.bg(1, n==9? 6 : 4), dirty, 2, vram[n-1]); + } + if(n == 9 && sel == VRAMConfig::obj1) mapVram(&vmap.obj(1, 0), dirty, 8, vram[n-1]); + if(n == 8 && sel == VRAMConfig::bgpal1) mapVram(&vmap.bgpal[1][0], dirty, 8, vram[n-1]); + if(n == 9 && sel == VRAMConfig::objpal1) mapVram(&vmap.objpal[1][0], dirty, 8, vram[n-1]); + if(n == 8 && sel == VRAMConfig::display) mapVram(&vmap.arm9[4][38], dirty, 2, vram[n-1]); + if(n == 9 && sel == VRAMConfig::display) mapVram(&vmap.arm9[4][40], dirty, 1, vram[n-1]); + } + + // Still unimplemented: bank[7] for SWRAM + // (currently both ARM7 and ARM9 have access) + + // Apply mirroring to address spaces smaller than 512K + // Only needed in cases where it's possible to read out of bounds. + for(unsigned n = 0; n < 8; n++) { + // OBJ0 - 256K + vmap.obj(0, n+16) = vmap.obj(0, n+0); + vmap.obj(0, n+24) = vmap.obj(0, n+8); + // BG1, OBJ1 - 128K + vmap.bg(1, n+ 8) = vmap.bg(1, n); + vmap.bg(1, n+16) = vmap.bg(1, n); + vmap.bg(1, n+24) = vmap.bg(1, n); + vmap.obj(1, n+ 8) = vmap.obj(1, n); + vmap.obj(1, n+16) = vmap.obj(1, n); + vmap.obj(1, n+24) = vmap.obj(1, n); + } + + for(unsigned i = 0; i < 4; i++) + for(unsigned n = 0; n < 32; n++) + vmap.arm9[i][n+32] = vmap.arm9[i][n+0]; +} + +uint32 System::regVmap(unsigned index) { + if(index == 0) return vmap.regs[3]<<24 | vmap.regs[2]<<16 | vmap.regs[1]<<8 | vmap.regs[0]<<0; + if(index == 1) return vmap.regs[7]<<24 | vmap.regs[6]<<16 | vmap.regs[5]<<8 | vmap.regs[4]<<0; + if(index == 2) return vmap.regs[9]<<8 | vmap.regs[8]<<0; +} + +void System::regVmap(unsigned index, uint32 data, uint32 mask) { + if(mask & 0x000000ff) vmap.regs[4*index + 0] = data>>0; + if(mask & 0x0000ff00) vmap.regs[4*index + 1] = data>>8; + if(mask & 0x00ff0000 && index < 2) vmap.regs[4*index + 2] = data>>16; + if(mask & 0xff000000 && index < 2) vmap.regs[4*index + 3] = data>>24; + + updateVmap(); +} + + + +void System::loadArm7Bios(const stream& stream) { + delete[] arm7.bios.data; + + arm7.bios.size = stream.size(); + arm7.bios.data = new uint32[(arm7.bios.size + 3)/4]; + + for(unsigned n = 0; n < arm7.bios.size; n += 4) + arm7.bios.write(n, Word, stream.readl(4)); +} + + +void System::loadArm9Bios(const stream& stream) { + delete[] arm9.bios.data; + + arm9.bios.size = stream.size(); + arm9.bios.data = new uint32[(arm9.bios.size + 3)/4]; + + for(unsigned n = 0; n < arm9.bios.size; n += 4) + arm9.bios.write(n, Word, stream.readl(4)); +} + + +void System::loadFirmware(const stream& stream) { + delete[] firmware.data; + + firmware.size = stream.size(); + firmware.data = new uint8[firmware.size]; + for(unsigned n = 0; n < firmware.size; n++) + firmware.write(n, Byte, stream.read()); +} + +void System::saveFirmware(const stream& stream) { + for(unsigned n = 0; n < firmware.size; n++) + stream.write(firmware.read(n, Byte)); +} + + +void System::loadRTC(const stream& stream) { + struct timeval cur = {}; + gettimeofday(&cur, 0); + + clock.reset(); + clock.stoppedSec = cur.tv_sec; + clock.stoppedUSec = cur.tv_usec; + + if(!stream.size()) return; + + uint8* xml = new uint8[stream.size() + 1]; + stream.read(xml, stream.size()); + xml[stream.size()] = 0; + + XML::Document document((const char*)xml); + delete[] xml; + + if(document["rtc"].exists() == false) + return; + + auto &rtc = document["rtc"]; + //string model = rtc["model"].data; + + if(rtc["settings"].exists()) { + clock.status1 = hex(rtc["settings"]["status"].data); + clock.status2 = hex(rtc["settings"]["mode"].data); + clock.adjust = hex(rtc["settings"]["adjust"].data); + clock.userByte = hex(rtc["settings"]["scratch"].data); + } + if(rtc["clock"].exists()) { + lstring date = rtc["clock"]["date"].data.split("/"); + lstring time = rtc["clock"]["time"].data.split(":"); + string wday = rtc["clock"]["day"].data; + + if(date.size() >= 3 && time.size() >= 3) { + string sec = time[2]; + string frac = "0"; + + if(sec.position(".")) { + frac = sec.split(".")[1]; + sec = sec.split(".")[0]; + } + clock.weekday = hex(wday) & 0x07; + clock.year = hex(date[0]) & 0xff; + clock.month = hex(date[1]) & 0x1f; + clock.day = hex(date[2]) & 0x3f; + clock.hour = hex(time[0]) & 0x3f; + clock.minute = hex(time[1]) & 0x7f; + clock.second = hex(sec) & 0x7f; + clock.counter = hex(frac); + } + } + + for(unsigned i = 0; i < 2; i++) { + string alarm = {"alarm", i+1}; + if(rtc[alarm].exists() == false) continue; + + string wday = rtc[alarm]["day"].data; + lstring time = rtc[alarm]["time"].data.split(":"); + lstring mode = rtc[alarm]["mode"].data.split(","); + + clock.alarm[i].setting[0] = hex(wday) & 0x07; + + if(time.size() >= 2) { + clock.alarm[i].setting[1] = hex(time[0]) & 0x7f; + clock.alarm[i].setting[2] = hex(time[1]) & 0x7f; + } + for(auto &select : mode) { + if(select.iequals("day")) clock.alarm[i].weekday |= 0x80; + if(select.iequals("hour")) clock.alarm[i].hour |= 0x80; + if(select.iequals("minute")) clock.alarm[i].minute |= 0x80; + } + } + + if(rtc["saved"].exists()) { + lstring savedOn = rtc["saved"]["on"].data.split("/"); + lstring savedAt = rtc["saved"]["at"].data.split(":"); + string savedDst = rtc["saved"]["dst"].data; + + if(savedOn.size() >= 3 && savedAt.size() >= 3) { + struct tm last = {}; + string sec = savedAt[2]; + string usec = "0"; + + if(sec.position(".")) { + usec = sec.split(".")[1]; + sec = sec.split(".")[0]; + } + last.tm_isdst = savedDst != ""? integer(savedDst) : -1; + last.tm_yday = -1; + last.tm_year = decimal(savedOn[0]) - 1900; + last.tm_mon = decimal(savedOn[1]) - 1; + last.tm_mday = decimal(savedOn[2]); + last.tm_wday = -1; + last.tm_hour = decimal(savedAt[0]); + last.tm_min = decimal(savedAt[1]); + last.tm_sec = decimal(sec); + + struct timeval now = {}; + gettimeofday(&now, nullptr); + + clock.freeze(timegm(&last), decimal(usec)); + clock.thaw(now.tv_sec, now.tv_usec); + } + } +} + + +void System::saveRTC(const stream& stream) { + struct timeval tv = {}; + gettimeofday(&tv, nullptr); + clock.thaw(tv.tv_sec, tv.tv_usec); + clock.freeze(tv.tv_sec, tv.tv_usec); + + struct tm now = *gmtime(&tv.tv_sec); + + string saveDate = { decimal(1900 + now.tm_year), "/", decimal<2,'0'>(now.tm_mon+1), "/", decimal<2,'0'>(now.tm_mday) }; + string saveTime = { decimal<2,'0'>(now.tm_hour), ":", decimal<2,'0'>(now.tm_min), ":", decimal<2,'0'>(now.tm_sec), ".", decimal<6,'0'>(tv.tv_usec) }; + + string dateStr = { hex<4>(0x2000 + clock.year), "/", hex<2>(clock.month), "/", hex<2>(clock.day) }; + string timeStr = { hex<2>(clock.hour), ":", hex<2>(clock.minute), ":", hex<2>(clock.second), ".", hex<4>(clock.counter) }; + + string alarmTime[2], alarmDay[2], alarmMode[2]; + + for(unsigned i = 0; i < 2; i++) { + lstring conditions; + if(clock.alarm[i].weekday & 0x80) conditions[i].append("day"); + if(clock.alarm[i].hour & 0x80) conditions[i].append("hour"); + if(clock.alarm[i].minute & 0x80) conditions[i].append("minute"); + + alarmMode[i] = conditions.concatenate(","); + alarmDay[i] = hex<1>(clock.alarm[i].weekday & 7); + alarmTime[i] = { hex<2>(clock.alarm[i].hour & 0x3f), + ":", hex<2>(clock.alarm[i].minute & 0x7f) }; + }; + + string xml{ + "\n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + "" + }; + stream.write((uint8*)(const char*)xml, xml.length()); +} + + + +void System::power() { + // Clear memory + memset(ewram.data, 0, ewram.size); + memset(iwram.data, 0, iwram.size); + memset(swram[0].data, 0, swram[0].size); + memset(swram[1].data, 0, swram[1].size); + memset(unmappedVram, 0, sizeof unmappedVram); + + for(unsigned n = 0; n < 9; n++) + memset(vram[n].data, 0, vram[n].size); + + // Reset VRAM mappings + for(auto &r : vmap.regs) r = 0x00; + clearVmap(); + memset(vmap.dirty, 0xff, sizeof vmap.dirty); + + arm9.config.arm9 = true; + arm9.config.arm7 = false; + arm7.config.arm9 = false; + arm7.config.arm7 = true; + arm9.other = &arm7; + arm7.other = &arm9; + + ppu[0].which = 0; + ppu[1].which = 1; + + arm7.power(); + arm9.power(); + clock.power(); + powerMgr.power(); + firmware.power(); + touchscreen.power(); + slot1.power(); + video.power(); + gpu.power(); + ppu[0].power(); + ppu[1].power(); + apu.power(); + wifi.power(); + + callerThread = co_active(); + activeThread = arm7.thread; // Required since right now ARM7 loads the binaries.. +} + +void System::run() { + callerThread = co_active(); + co_switch(activeThread); +} + +void System::frame() { + interface->videoRefresh(video.output, 256*4, 256, 384); + activeThread = co_active(); + co_switch(callerThread); +} + +#include "clock.cpp" +#include "powermgr.cpp" +#include "touchscreen.cpp" + +} diff --git a/bsnes/nds/system/system.hpp b/bsnes/nds/system/system.hpp new file mode 100644 index 00000000..e1d8a73c --- /dev/null +++ b/bsnes/nds/system/system.hpp @@ -0,0 +1,231 @@ +#include "eventqueue.hpp" + +typedef function Action; +typedef EventQueue_of EventQueue; +typedef EventQueue_of::Elem Event; + + +enum class Input : unsigned { + // REG_KEYINPUT (10 bits) + A, B, Select, Start, Right, Left, Up, Down, R, L, + + // REG_AUXINPUT (8 bits) + // - C, Z, W seem present, but unconnected + // - D is supposedly on debug units + X, Y, C, D, Z, W, Pen, Lid, + + // Touchscreen + PenX, PenY, PenZ1, PenZ2, +}; + + +struct SPIDevice { + virtual ~SPIDevice(); + virtual void power() = 0; + virtual void select(bool state) = 0; + virtual uint8 transfer(uint8 data) = 0; +}; + +#include "../memory/eeprom.hpp" +#include "../memory/fram.hpp" +#include "../memory/flash.hpp" + +struct PowerMgr : SPIDevice { + ~PowerMgr(); + void power(); + void select(bool state); + uint8 transfer(uint8 data); +}; + + +struct Touchscreen : SPIDevice { + ~Touchscreen(); + void power(); + void select(bool state); + uint8 transfer(uint8 data); + + bool penDown(); + + uint1 bitDepth; enum { read12, read8 }; + uint1 refMode; enum { diff, single }; + uint2 powerMode; enum { powerAuto, powerADC, powerRef, powerFull }; + uint3 input; enum { + temp0 = 0, temp1 = 7, + vbatt = 2, aux = 6, + ypos = 1, xpos = 5, + pressure0 = 3, pressure1 = 4, + }; + + uint32 adc; + uint12 last; +}; + + +struct Clock { + Clock(); + ~Clock(); + void reset(); + void power(); + uint4 io(uint4 pins); + + void dateTime(); + void alarmTime(unsigned no); + void field(uint8& src, uint8 mask); + + void tick(); + void tickSecond(); + void tickDay(); + bool incBCD(uint8& val, uint8 first, uint8 last); + + void freeze(int64 curSec, int64 curUSec); + void thaw(int64 curSec, int64 curUSec); + + + int64 stoppedSec, stoppedUSec; + + uint1 lastCs, lastClk; + uint8 buffer, dataOut; + uint3 nbits; + uint8 command, index; + bool output; + + uint8 status1; enum { + resetBit = 0x01, hourMode = 0x02, + int1Flag = 0x10, int2Flag = 0x20, + powerLow = 0x40, powerLost = 0x80 + }; + uint8 status2; enum { + int1Mode = 0x0f, + int2Mode = 0x40, testMode = 0x80 + }; + uint8 adjust; // clock rate fine adjustment + uint8 userByte; + + Event event; + uint16 counter; // 32KHz subsecond counter + uint1 intr[2]; // Interrupts (both go to IRQ pin) + uint1 hold; // Delays seconds tick while reading the time + uint16 lag; // How long the seconds tick was delayed + uint1 secondsTickPending; + + union { + struct { uint8 year, month, day, weekday, hour, minute, second; }; + struct { uint8 time[7]; }; + }; + union { + struct { uint8 weekday, hour, minute; }; + struct { uint8 setting[3]; }; + } alarm[2]; +}; + + +struct VRAMMapping : HalfMemory { + VRAMMapping(); + VRAMMapping(HalfMemory& target, uint8* dirtyBits, unsigned pageno); + ~VRAMMapping(); + + uint16& operator[](uint32 addr); + uint32 read(uint32 addr, uint32 size); + void write(uint32 addr, uint32 size, uint32 word); + bool dirty(uint32 addr); + void clearDirty(uint32 addr, uint32 size); + + uint8 *dirtyBits; +}; + + +struct System { + cothread_t callerThread; + cothread_t activeThread; + bool running; + + Flash firmware; + Touchscreen touchscreen; + PowerMgr powerMgr; + Clock clock; + + SDRAM ewram; // 4MB shared external WRAM + SRAM iwram; // 64KB 32-bit work RAM, private to ARM7 + SRAM swram[2]; // 16KB x 2 banks switchable 32-bit WRAM + HalfMemory vram[9]; // 656KB in 9 banks of 16-bit VRAM + HalfMemory wxram; // 8KB wireless packet buffer + + uint16 unmappedVram[0x2000]; + + struct VRAMConfig { + uint1 enable; + uint2 offset; + uint3 bus; // aka. MST or "Magic Selector Thing" + enum { + display=0, // all banks + bg0=1, // A,B,C,D,E,F,G + obj0=2, // A,B, E,F,G + arm7=2, // C,D + tex=3, // A,B,C,D + texpal=3, // E,F,G + bgpal0=4, // E,F,G + objpal0=5, // E?,F,G + ppu1=4, // C,D + bg1=1, // H,I + obj1=2, // I + bgpal1=2, // H + objpal1=3, // I + }; + + operator uint8() { + return enable<<7 | offset<<3 | bus<<0; + } + VRAMConfig& operator=(uint8 data) { + enable = data>>7; + offset = data>>3; + bus = data>>0; + return *this; + } + }; + + struct { + // Mappings for each graphics bus that can have VRAM banked onto it. + // Each page is 16K, the finest granularity. + VRAMMapping arm9[8][64]; // 8x1M arm9 map - 0x060,062,064,066,068,.. + VRAMMapping arm7[16]; // 256K arm7 map - 0x060.. + + // Locked memory can be used by the GPU, but isn't mapped in CPU space. + VRAMMapping tex[32]; // 512K locked texture memory + VRAMMapping texpal[8]; // 128K locked texture palettes + VRAMMapping bgpal[2][8]; // 32K locked BG palettes + VRAMMapping objpal[2][8]; // 8K locked OBJ palettes + + VRAMMapping &bg(int w, int i) { return arm9[0+w][i]; } + VRAMMapping &obj(int w, int i) { return arm9[2+w][i]; } + VRAMMapping &display(int i) { return arm9[4][i&31]; } + + VRAMConfig regs[10]; // A,B,C,D, E,F,G,SWRAM, H,I + + uint8 dirty[(512 + 96 + 48)*1024 / 256]; + } vmap; + + + void clearVmap(); + void updateVmap(); + void mapVram(VRAMMapping* loc, uint8 *dirtyBits, unsigned npages, HalfMemory& bank); + + uint32 regVmap(unsigned index); + void regVmap(unsigned index, uint32 data, uint32 mask); + + void loadArm7Bios(const stream&); + void loadArm9Bios(const stream&); + void loadFirmware(const stream&); + void loadRTC(const stream&); + + void saveFirmware(const stream&); + void saveRTC(const stream&); + + void power(); + void run(); + + void frame(); + + System(); +}; + +extern System system; diff --git a/bsnes/nds/system/touchscreen.cpp b/bsnes/nds/system/touchscreen.cpp new file mode 100644 index 00000000..0db32907 --- /dev/null +++ b/bsnes/nds/system/touchscreen.cpp @@ -0,0 +1,112 @@ + +Touchscreen::~Touchscreen() { } + +void Touchscreen::power() { + input = 0; + bitDepth = 0; + refMode = 0; + powerMode = 0; + adc = 0; + last = 0; +} + +void Touchscreen::select(bool state) { + if(state) return; + + adc = 0; +} + +bool Touchscreen::penDown() { + if(powerMode == 3) return true; // differs between NDS Lite and original? + + signed x = interface->inputPoll(ID::Port::Touchpad, 0, ID::Touchpad::X); + signed y = interface->inputPoll(ID::Port::Touchpad, 0, ID::Touchpad::Y); + signed p = interface->inputPoll(ID::Port::Touchpad, 0, ID::Touchpad::Pressure); + signed d = 0;//interface->inputPoll(ID::Port::Touchpad, 0, ID::Touchpad::PressureD); + + if(y < 0) y = -0x8000; + + if(x == -0x8000 || y == -0x8000) { + return 0; // no touch input + } + if(p == -0x8000) // no analog pressure + p = d? 0 : -0x7fff; // use digital + + return p > -0x7ff0; +} + +uint8 Touchscreen::transfer(uint8 data) { + if(data & 0x80) { + // Start a new measurement + input = data>>4; + bitDepth = data>>3; + refMode = data>>2; + powerMode = data>>0; + + signed NONE = -0x8000; + signed x = interface->inputPoll(ID::Port::Touchpad, 0, ID::Touchpad::X); + signed y = interface->inputPoll(ID::Port::Touchpad, 0, ID::Touchpad::Y); + signed p = interface->inputPoll(ID::Port::Touchpad, 0, ID::Touchpad::Pressure); + signed d = 0;//interface->inputPoll(ID::Port::Touchpad, 0, ID::Touchpad::PressureD); + + if(p==NONE) p = !d? -0x7fff : -0x3fff; // no analog? use digital pen + if(x==NONE || y==NONE) p = NONE; // check if pen offscreen + if(y < 0) p = NONE; // restrict to bottom screen + + x += 0x7fff; y *= 2; + p += 0x7fff; + + if(p > 0) { + signed z1 = 0x000, z2 = 0xfff, r = 0xffff - p; + if(x > 0) { // bleh, div-by-zero, just use medium pressure for now + z1 = 0xc00; //0xffffff / (0x1000 + 0x1000/x + 0x1000*(r - y)/x); + z2 = 0x400; //z1*(0x1000 + 0x1000*r/x) / 0x1000; + } + x /= 16; + y /= 16; + + // Without any pressure, there's no connection, and the input floats. + // The measurements seem to return previous values to some extent. + if(input == xpos) last = x; // y+ (along x-/x+ axis) + if(input == ypos) last = y; // x+ (along y-/y+ axis) + if(input == pressure0) last = z1; // x+ (along x-/y+ diagonal?) + if(input == pressure1) last = z2; // y- (along x-/y+ diagonal?) + } + + signed vref = 0x34cc; // reference = 3.3V + signed room = (273 + 25)*0x1000; // 25*C in kelvin + signed k = room; + signed t1 = 0x1000*600 - (k-room)*21/10; // t1 = 600mV @ room - 2.1mV/*K + error + signed t2 = t1 + k * 0x1000/0x292b; // t2 = t1 + k/2.573 + + if(input == temp0) last = t1 * 0xfff/vref; // temperature + if(input == temp1) last = t2 * 0xfff/vref; // temp (w/bias) + if(input == vbatt) last = 0x000; // grounded + if(input == aux) { + // This was split into two inputs - reference is always "single" mode + if(refMode==single) last = 0x800; // microphone + if(refMode==diff) last = 0xfff; // Vcc (NDS Lite) + } + + adc |= last; + + // 8-bit isn't any faster since you have to read two bytes over the serial + // interface either way. Bumping the clock to 4MHz may not provide enough + // time for the ADC to settle, producing less accurate results. + if(bitDepth == read8) + adc &= ~0xf; + } + // Response is 1 bit delay + 8 or 12 bits data. + // This causes some misalignment: + // -------- 0hhhhhhhlllll - after command + // 0hhhhhhh lllll000----- - after first read + // lllll000 [0hhhhhhhlllll] - after second read [+ command] + // [0hhhhhhh lllll000-----] - ... + // [lllll000 0hhhhhhhlllll] - + // response next data + // + // It's perfectly legit (and common) to send a new command while reading the + // low byte. By doing this, you receive a stream of readings with no gaps or + // command overhead in between. + return adc <<= 8, adc >> 21; +} diff --git a/bsnes/nds/video/video.cpp b/bsnes/nds/video/video.cpp new file mode 100644 index 00000000..5c535b79 --- /dev/null +++ b/bsnes/nds/video/video.cpp @@ -0,0 +1,180 @@ +#include + +namespace NintendoDS { + +Video video; + +void Video::scanline(unsigned y) { + gpu.scanline(); + ppu[0].scanline(); + ppu[1].scanline(); + + if(line < 192) { + bool display = source[0] == srcFrameBuffer; + bool read = write && sourceB == srcFrameBuffer; + + unsigned srcline = y + 64*(frameBuffer & (display? 0xc : 0xf)); + unsigned destline = y + 64*targetBuffer; + + uint16 *src = &system.vmap.display(srcline / 32)[512*(srcline % 32)]; + uint16 *dest = &system.vmap.display(destline / 32)[512*(destline % 32)]; + + if(read || display) { + for(unsigned x = 0; x < 256; x++) { + uint16 c = src[x]; + uint5 r = c>>0, g = c>>5, b = c>>10; + + frameBufData[x] = b<<13 | g<<7 | r<<1; + } + } + if(write) { + uint32 *aData = sourceA == srcGPU? &gpu.output[256*line] : ppu[0].output; + uint32 *bData = sourceB == srcFifo? fifoData : frameBufData; + + unsigned af = min((unsigned)blendAf, 16u); + unsigned bf = min((unsigned)blendBf, 16u); + + if(targetSource == 0) af = 16, bf = 0; + if(targetSource == 1) af = 0, bf = 16; + + // Need to see what happens with alpha bit.. + for(unsigned x = 0; x < 256; x++) { + uint32 a = aData[x], b = bData[x]; + + uint6 ar = a>>0, ag = a>>6, ab = a>>12; + uint6 br = b>>0, bg = b>>6, bb = b>>12; + + ar = (ar*af + br*bf + 8) / 32u; + ag = (ag*af + bg*bf + 8) / 32u; + ab = (ab*af + bb*bf + 8) / 32u; + + dest[x] = 0x8000 | ab<<10 | ag<<5 | ar<<0; + } + } + + uint32* line[2] = { &output[256*(y + 192*(ppu0Screen == 0))], + &output[256*(y + 192*(ppu0Screen == 1))] }; + + if(source[0] == srcNone) memcpy(line[0], blankData, 256*4); + if(source[0] == srcPPU) memcpy(line[0], ppu[0].output, 256*4); + if(source[0] == srcFrameBuffer) memcpy(line[0], frameBufData, 256*4); + if(source[0] == srcFifo) memcpy(line[0], fifoData, 256*4); + + if(source[1] == srcNone) memcpy(line[1], blankData, 256*4); + if(source[1] == srcPPU) memcpy(line[1], ppu[1].output, 256*4); + if(source[1] == srcFrameBuffer) memcpy(line[1], blankData, 256*4); + if(source[1] == srcFifo) memcpy(line[1], blankData, 256*4); + + for(unsigned s = 0; s < 2; s++) { + if(!fade[s] || !blendYf[s]) continue; + + uint64 yf = min(32, 2*blendYf[s]); + uint64 y = 02000200020; + if(fade[s] == lighten) + y += 07700770077*yf; + + for(unsigned x = 0; x < 256; x++) { + uint64 bgr = (line[s][x] & 0777777)*01000001ull & 07700770077ull; + + bgr = (bgr*(32-yf) + y)/32; + + if(bgr & 010000000000) bgr |= 007700000000; + if(bgr & 000001000000) bgr |= 000000770000; + if(bgr & 000000000100) bgr |= 000000000077; + bgr &= 007700770077; + + line[s][x] = (bgr | bgr>>18) & 0777777; + } + } + } +} + +uint32 Video::regCapture() { + return blendAf<<0 | blendBf<<8 + | (targetBuffer<<14 & 3<<16) + | (targetBuffer<<18 & 3<<18) + | (frameBuffer<<26 & 3<<26) + | (sourceA == srcGPU? 1<<24 : 0) + | (sourceB == srcFifo? 1<<25 : 0) + | targetSource<<29 | write<<31; +} + +void Video::regCapture(uint32 data, uint32 mask) { + if(mask & 0x000000ff) { + blendAf = data>>0; + } + if(mask & 0x0000ff00) { + blendBf = data>>8; + } + if(mask & 0x00ff0000) { + targetBuffer = data>>14 & 0xc; + targetBuffer += data>>18 & 0x3; + targetSize = data>>20; + } + if(mask & 0xff000000) { + frameBuffer &= ~3; + frameBuffer += data>>26 & 0x3; + sourceA = data & 1<<24? srcGPU : srcPPU; + sourceB = data & 1<<25? srcFifo : srcFrameBuffer; + targetSource = data>>29; + write = data>>31; + } +} + +void Video::regFifo(uint32 data) { +} + +uint32 Video::regBrightness(unsigned index) { + return fade[index]<<14 | blendYf[index]<<0; +} + +void Video::regBrightness(unsigned index, uint32 data, uint32 mask) { + if(mask & 0x001f) blendYf[index] = data>>0; + if(mask & 0xc000) fade[index] = data>>14; +} + + +void Video::power() { + for(unsigned x = 0; x < 256; x++) + blankData[x] = 0x3ffff; + + line = 262; + ppu0Screen = 0; + source[0] = srcNone; + source[1] = srcNone; + frameBuffer = 0; + fade[0] = 0; + fade[1] = 0; + blendYf[0] = 0; + blendYf[1] = 0; + + write = false; + sourceA = srcNone; + sourceB = srcNone; + blendAf = blendBf = 0; + targetBuffer = 0; + + hdrawEvent.action = [&]() { + if(++line == 263) { + line = 0; + } + if(line == 192) { + write = false; + system.frame(); + } + scanline(line); + arm9.event.queue.add(12*256, hblankEvent); + arm7.hdraw(); + arm9.hdraw(); + }; + + hblankEvent.action = [&]() { + arm9.event.queue.add(12*99, hdrawEvent); + arm7.hblank(); + arm9.hblank(); + }; + + arm9.event.queue.add(0, hdrawEvent); +} + +} diff --git a/bsnes/nds/video/video.hpp b/bsnes/nds/video/video.hpp new file mode 100644 index 00000000..b3df3fa8 --- /dev/null +++ b/bsnes/nds/video/video.hpp @@ -0,0 +1,44 @@ +struct Video { + void power(); + void scanline(unsigned y); + + uint32 regCapture(); + void regCapture(uint32 data, uint32 mask); + void regFifo(uint32 data); + + uint32 regBrightness(unsigned index); + void regBrightness(unsigned index, uint32 data, uint32 mask); + + uint32 output[256*384]; + + uint32 blankData[256]; + uint32 frameBufData[256]; + uint32 fifoData[256]; + + uint9 line; + Event hdrawEvent; + Event hblankEvent; + + // Display and rendering on NDS are more loosely coupled, although + // the GPU and PPUs are still all locked to 60fps. + enum { srcNone, srcPPU, srcFrameBuffer, srcFifo, srcGPU }; + + // For display onscreen + uint1 screensPowered; + uint1 ppu0Screen; // 0 is bottom, 1 is top + int source[2]; + int fade[2]; enum { lighten=1, darken=2 }; + uint5 blendYf[2]; + + // For rendering to VRAM + bool write; + int sourceA; // PPU0 or GPU + int sourceB; // framebuffer or FIFO + uint5 blendAf, blendBf; // for blending A + B + uint2 targetSize; + uint2 targetSource; + uint4 targetBuffer; + uint4 frameBuffer; +}; + +extern Video video; diff --git a/bsnes/nds/wifi/wifi.cpp b/bsnes/nds/wifi/wifi.cpp new file mode 100644 index 00000000..dfebb566 --- /dev/null +++ b/bsnes/nds/wifi/wifi.cpp @@ -0,0 +1,488 @@ +#include + +namespace NintendoDS { + +WIFI wifi; + + +void WIFI::power() { + // This isn't really cleared but we have to be deterministic. + memset(system.wxram.data, 0, system.wxram.size); + + powered = true; + + reg004 = 0; + reg034 = 0; + swMode = 0; + wepMode = 0; + memset(macAddr, 0, sizeof macAddr); + memset(bssId, 0, sizeof bssId); + assocIdl = 0; + assocIdf = 0; + + rxControl = 0; + wepControl = 0; + reg034 = 0; + baseBandPower = 0; + + interrupt.flags = 0; + interrupt.enable = 0; + interrupt.counterFlags = 0; + interrupt.counterEnable = 0; + interrupt.oflowFlags = 0; + interrupt.oflowEnable = 0; + + pm.txIdle = 0; + pm.wakeRequest = 0; + pm.wakePending = 0; + pm.sleeping = 0; + + bb.event.action = [&]() { bbTransferBit(); }; + bb.time = 0; + bb.busy = 0; + bb.read = 0; + bb.write = 0; + bb.header = 0; + bb.powerl = 0; + bb.powerh = 0; + bb.mode8 = 0; + bb.modeE = 0; + bb.clock = 0; + + memset(bb.regs, 0, sizeof bb.regs); + + bb.regs[0x00] = 0x6d; + bb.regs[0x4d] = 0xff; + bb.regs[0x5d] = 0x01; + bb.regs[0x64] = 0xff; + + rf.event.action = [&]() { rfTransferBit(); }; + rf.time = 0; + rf.busy = 0; + rf.data = 0; + rf.length = 24; + rf.type = 0; + rf.reserved = 0; + + memset(rf.regs, 0, sizeof rf.regs); + + rf.regs[0x00] = 0x00007; + rf.regs[0x01] = 0x09003; + rf.regs[0x02] = 0x00022; + rf.regs[0x03] = 0x1ff78; + rf.regs[0x04] = 0x09003; + rf.regs[0x05] = 0x01780; + rf.regs[0x06] = 0x00000; + rf.regs[0x07] = 0x14578; + rf.regs[0x08] = 0x1e742; + rf.regs[0x09] = 0x00120; + rf.regs[0x0a] = 0x00000; + rf.regs[0x0b] = 0x00000; + rf.regs[0x0c] = 0x00000; + rf.regs[0x1b] = 0x0000f; + rf.regs[0x0e] = 0x00022; + rf.regs[0x1f] = 0x00001; + + txWritePos = 0; rxBufBegin = 0; + txWriteCounter = 0; rxBufEnd = 0; + txGapBegin = 0; rxWritePos = 0; + txGapSize = 0; rxWritePosLatch = 0; + txTimOffset = 0; rxReadPos = 0; + txBeacon = 0; rxSoftReadPos = 0; + txMultiCmd = 0; rxReadCounter = 0; + txSlots[0] = 0; rxGapBegin = 0; + txSlots[1] = 0; rxGapSize = 0; + txSlots[2] = 0; reg00a = 0; + txStatControl = 0; + txRetryLimit = 0; + + reg1a0l = 0; + reg1a0m = 0; + reg1a0n = 0; + reg1a0h = 0; + reg1a2 = 0; + reg1a4 = 0; + + listenCount = 0; + listenInterval = 0; + beaconInterval = 0; + preamble = 0; + random = 1; + + timer.enable = false; + timer.enableIrq = false; + timer.enableTxMP = false; + timer.count = 0; + timer.compare = 0; + + config120l = 0; config140 = 0; config154l = 0; + config120h = 0; config142 = 0; config154m = 0; + config122 = 0; config144 = 0; config154h = 0; + config124 = 0; config146 = 0; + config128 = 0; config148 = 0; config0d4 = 0; + config130 = 0; config14a = 0; config0d8 = 0; + config132l = 0; config14c = 0; config0da = 0; + config132h = 0; config150l = 0; config0ecl = 0; + configBeaconCount = 0; config150h = 0; config0ech = 0; + + stats.reg1b0 = 0; + stats.reg1b2 = 0; + stats.reg1b4 = 0; + stats.reg1b6 = 0; + stats.reg1b8 = 0; + stats.reg1ba = 0; + stats.reg1bc = 0; + stats.reg1be = 0; + stats.txErrors = 0; + stats.rxPackets = 0; + memset(stats.mpErrors, 0, sizeof stats.mpErrors); +} + +void WIFI::bbTransfer() { + // Assuming 22MHz (66MHz/3) clock here. Probably wrong. + bb.busy = 0; + bb.read = 0; + bb.time = 16 + 8; + arm7.event.queue.add(3, bb.event); +} + +void WIFI::bbTransferBit() { + if(--bb.time) { + // Small delay before setting busy bit + if(bb.time == 20) bb.busy = 1; + + arm7.event.queue.add(3, bb.event); + return; + } + // Finished, commit the read or write. + bb.busy = 0; + + uint1 start = bb.header>>14; + uint1 rd = bb.header>>13; + uint1 wr = bb.header>>12; + uint8 addr = bb.header>>0; + + if(start) { + if(rd) { + bb.read = addr < 0x69? bb.regs[addr] : 0; + //print("bb read ",hex<2>(addr)," = ",hex<2>(bb.read),"\n"); + } + if(wr) { + if(0x0d <= addr && addr <= 0x12) return; + if(0x16 <= addr && addr <= 0x1a) return; + if(0x5d <= addr && addr <= 0x61) return; + if(0x00 == addr || 0x27 == addr) return; + if(0x4d == addr || 0x64 == addr) return; + if(0x66 == addr || 0x69 <= addr) return; + + if(addr < 0x69) bb.regs[addr] = bb.write; + //print("bb write ",hex<2>(addr)," : ",hex<2>(bb.write),"\n"); + } + } +} + +void WIFI::rfTransfer() { + rf.busy = 1; + rf.time = 18 + 6; + arm7.event.queue.add(3, rf.event); +} + +void WIFI::rfTransferBit() { + if(--rf.time) { + arm7.event.queue.add(3, rf.event); + return; + } + //Finished, commit the read or write. + rf.busy = 0; + + uint1 rd = rf.data>>23; + uint5 addr = rf.data>>18; + uint18 data = rf.data>>0; + + if(rd) { + rf.data = rf.regs[addr]; + //print("rf read ",hex<2>(addr)," = ",hex<5>(rf.data),"\n"); + } + else { + rf.regs[addr] = data; + //print("rf write ",hex<2>(addr)," : ",hex<5>(data),"\n"); + } +} + +uint32 WIFI::read(uint32 addr, uint32 size) { + if(addr & 0x4000) + return system.wxram.read(addr & 0x1fff, size); + + if(size==Word) { return read(addr&~2, Half)<<0 + | read(addr| 2, Half)<<16; } + //if(addr != 0x480015e && addr != 0x4800180) + // print("wifi r ",hex<8>(addr),"\n"); + + switch(addr & 0xffe) { + case 0x000: return 0xc340; // chip ID + case 0x004: return reg004; + case 0x006: return swMode<<0 | wifi.wepMode<<3; + case 0x008: return txStatControl; + case 0x00a: return reg00a; + case 0x010: return interrupt.flags; + case 0x012: return interrupt.enable; + + case 0x018: return macAddr[0] | macAddr[1]<<8; + case 0x01a: return macAddr[2] | macAddr[3]<<8; + case 0x01c: return macAddr[4] | macAddr[5]<<8; + case 0x020: return bssId[0] | bssId[1]<<8; + case 0x022: return bssId[2] | bssId[3]<<8; + case 0x024: return bssId[4] | bssId[5]<<8; + case 0x028: return assocIdl; + case 0x02a: return assocIdf; + case 0x02c: return txRetryLimit; + + case 0x030: return rxControl; + case 0x032: return wepControl; + case 0x034: return reg034; + case 0x036: return bb.clock; + case 0x038: return pm.txIdle; + case 0x03c: return pm.wakeRequest | pm.wakePending<<8 | pm.sleeping<<9; + case 0x040: return 0;//wifi.pm.; + + case 0x044: { + uint11 data = random; + random = random<<1 | random>>10; + random ^= data & 1; + return data; + } + + case 0x050: return rxBufBegin; + case 0x052: return rxBufEnd; + case 0x054: return rxWritePos; + case 0x056: return rxWritePosLatch; + case 0x058: return rxReadPos<<1; + case 0x05a: return rxSoftReadPos; + case 0x05c: return rxReadCounter; + case 0x060: break;//return rxBufRead(); + case 0x062: return rxGapBegin<<1; + case 0x064: return rxGapSize; + + case 0x068: return txWritePos<<1; + case 0x06c: return txWriteCounter; + case 0x074: return txGapBegin<<1; + case 0x076: return txGapSize; + case 0x080: return txBeacon; + case 0x084: return txTimOffset; + case 0x088: return listenCount; + case 0x08c: return beaconInterval; + case 0x08e: return listenInterval; + + case 0x0bc: return preamble; + + case 0x0d4: return config0d4; + case 0x0d8: return config0d8; + case 0x0da: return config0da; + case 0x0e8: return timer.enable; + case 0x0ea: return timer.enableIrq; + case 0x0ec: return config0ecl | config0ech<<8; + case 0x0ee: return timer.enableTxMP; + + case 0x110: return preBeacon; + + case 0x120: return config120l | config120h<<15; + case 0x122: return config122; + case 0x124: return config124; + case 0x128: return config128; + case 0x130: return config130; + case 0x132: return config132l | config132h<<15; + case 0x134: return configBeaconCount; + case 0x140: return config140; + case 0x142: return config142; + case 0x144: return config144; + case 0x146: return config146; + case 0x148: return config148; + case 0x14a: return config14a; + case 0x14c: return config14c; + case 0x150: return config150l | config150h<<8; + case 0x154: return config154l | config154m<<9 | config154h<<11; + + case 0x15c: return bb.read; + case 0x15e: return bb.busy; + case 0x160: return bb.mode8<<8 | bb.modeE<<14; + case 0x168: return bb.powerl<<0 | bb.powerh<<15; + + case 0x17c: return rf.data>>16; + case 0x17e: return rf.data>>0; + case 0x180: return rf.busy; + + case 0x1a0: return reg1a0l | reg1a0m<<4 | reg1a0n<<8 | reg1a0h<<11; + case 0x1a2: return reg1a2; + case 0x1a4: return reg1a4; + + case 0x244: return 0x0000; + case 0x254: return 0xeeee; + case 0x290: return 0xffff; + } + //print("r ",hex<8>(addr),": unimplemented\n"); + return 0; +} + +void WIFI::write(uint32 addr, uint32 size, uint32 data) { + if(size==Byte) return; + if(size==Word) { write(addr&~2, Half, data & 0xffff); + write(addr| 2, Half, data >> 16); return; } + if(addr & 0x4000) + return system.wxram.write(addr & 0x1fff, Half, size); + + //print("wifi w ",hex<8>(addr)," : ",hex<4>(data),"\n"); + + switch(addr & 0xffe) { + case 0x004: + if((reg004 ^ data) & 1<<0) { + if(data & 1) { + reg034 = 0x2; + //rf.pins = 0x46; + //rf.status = 9; + //reg27c = 5; + //reg2a2 = ..; + } + else { + reg034 = 0xa; + } + } + if(data & 1<<13) { + rxWritePosLatch = 0; + //reg0c0 = 0; + //reg0c4 = 0; + //reg1a4 = 0; + //reg278 = 0xf; + } + if(data & 1<<14) { + swMode = 0; + wepMode = 0; + //txStatCnt = 0; + //reg00a = 0; + memset(macAddr, 0, sizeof macAddr); + memset(bssId, 0, sizeof bssId); + assocIdl = 0; + assocIdf = 0; + //txRetryLimit = 0; + //reg02e = 0; + rxBufBegin = 0x4000; + rxBufEnd = 0x4800; + txTimOffset = 0; + //reg0bc = 1; + //reg0d0 = 0x401; + config0d4 = 1; + //reg0e0 = 8; + config0ecl = 3; + config0ech = 0x3f; + //reg194 = 0; + //reg198 = 0; + //reg1a2 = 1; + //reg224 = 3; + //reg230 = 0x47; + } + reg004 = data; + return; + + case 0x006: swMode = data>>0; wepMode = data>>3; return; + case 0x008: txStatControl = data; return; + case 0x00a: reg00a = data; return; + case 0x21c: interrupt.flags |= data & ~0x400; return; + case 0x010: interrupt.flags &= ~data; return; + case 0x012: interrupt.enable = data; return; + + case 0x018: macAddr[0] = data; macAddr[1] = data>>8; return; + case 0x01a: macAddr[2] = data; macAddr[3] = data>>8; return; + case 0x01c: macAddr[4] = data; macAddr[5] = data>>8; return; + case 0x020: bssId[0] = data; bssId[1] = data>>8; return; + case 0x022: bssId[2] = data; bssId[3] = data>>8; return; + case 0x024: bssId[4] = data; bssId[5] = data>>8; return; + case 0x028: assocIdl = data; return; + case 0x02a: assocIdf = data; return; + case 0x02c: txRetryLimit = data; return; + + case 0x030: rxControl = data; return; + case 0x032: wepControl = data & 0x8000; return; + case 0x034: reg034 = data; return; + case 0x036: bb.clock = data; return; + case 0x038: pm.txIdle = data; return; + case 0x03c: pm.wakeRequest = data>>1; return; + case 0x040: if(data & 1<<15) { + reg034 = 2; + pm.sleeping = data>>0; + } + return; + + case 0x050: rxBufBegin = data; return; + case 0x052: rxBufEnd = data; return; + case 0x056: rxWritePosLatch = data; return; + case 0x058: rxReadPos = data>>1; return; + case 0x05a: rxSoftReadPos = data; return; + case 0x05c: rxReadCounter = data; return; + case 0x062: rxGapBegin = data>>1; return; + case 0x064: rxGapSize = data; return; + + case 0x068: txWritePos = data>>1; return; + case 0x06c: txWriteCounter = data; return; + case 0x070: break;//return txBufWrite(data); + case 0x074: txGapBegin = data>>1; return; + case 0x076: txGapSize = data; return; + + case 0x080: txBeacon = data; return; + case 0x084: txTimOffset = data; return; + case 0x088: listenCount = data; return; + case 0x08c: beaconInterval = data; return; + case 0x08e: listenInterval = data; return; + + case 0x0b4: return; //txBufReset + case 0x0bc: preamble = data; return; + + case 0x0d4: config0d4 = data; return; + case 0x0d8: config0d8 = data; return; + case 0x0da: config0da = data; return; + case 0x0e8: timer.enable = data; return; + case 0x0ec: config0ecl = data; config0ech = data>>8; return; + case 0x0ea: timer.enableIrq = data; return;//if bit 1 trigger irq14 + case 0x0ee: timer.enableTxMP = data; return; + + case 0x110: preBeacon = data; return; + + case 0x120: config120l = data; config120h = data>>15; return; + case 0x122: config122 = data; return; + case 0x124: config124 = data; return; + case 0x128: config128 = data; return; + case 0x130: config130 = data; return; + case 0x132: config132l = data; config132h = data>>15; return; + case 0x134: configBeaconCount = data; return; + case 0x140: config140 = data; return; + case 0x142: config142 = data; return; + case 0x144: config144 = data; return; + case 0x146: config146 = data; return; + case 0x148: config148 = data; return; + case 0x14a: config14a = data; return; + case 0x14c: config14c = data; return; + case 0x150: config150l = data; config150h = data>>8; return; + case 0x154: config154l = data; config154m = data>>9; config154h = data>>11; return; + + case 0x158: bb.header = data; return wifi.bbTransfer(); + case 0x15a: bb.write = data; return; + case 0x160: bb.mode8 = data>>8; bb.modeE = data>>14; return; + case 0x168: bb.powerl = data>>0; bb.powerh = data>>15; return; + + case 0x17c: rf.data &= 0xffff; rf.data |= data<<16; return wifi.rfTransfer(); + case 0x17e: rf.data &= ~0xffff; rf.data |= data<<0; return; + case 0x184: rf.length = data>>0; + rf.type = data>>8; + rf.reserved = data>>14; return; + + case 0x1a0: reg1a0l = data; reg1a0m = data>>4; reg1a0n = data>>8; reg1a0h = data>>11; return; + case 0x1a2: reg1a2 = data; return; + case 0x1a4: reg1a4 = data; return; + + case 0x244: return; + case 0x254: return; + case 0x290: return; + } + //print("w ",hex<8>(addr),": unimplemented\n"); +} + + +} diff --git a/bsnes/nds/wifi/wifi.hpp b/bsnes/nds/wifi/wifi.hpp new file mode 100644 index 00000000..548940e6 --- /dev/null +++ b/bsnes/nds/wifi/wifi.hpp @@ -0,0 +1,153 @@ + +struct WIFI { + void power(); + + void bbTransfer(); + void bbTransferBit(); + + void rfTransfer(); + void rfTransferBit(); + + uint32 read(uint32 addr, uint32 size); + void write(uint32 addr, uint32 size, uint32 data); + + uint1 powered; + + uint16 reg004; + uint3 swMode, wepMode; + + uint8 macAddr[6]; + uint8 bssId[6]; + uint4 assocIdl; + uint11 assocIdf; + + uint16 rxControl, wepControl; + uint16 reg034, baseBandPower; + + uint16 rxBufBegin, rxBufEnd; + uint12 rxWritePos, rxWritePosLatch; + uint12 rxReadPos, rxSoftReadPos; + uint12 rxGapBegin, rxGapSize; + uint12 rxReadCounter; + uint16 reg00a; + + uint12 txWritePos; + uint12 txGapBegin, txGapSize; + uint16 txBeacon; + uint16 txMultiCmd; + uint16 txSlots[3]; + uint8 txTimOffset; + uint12 txWriteCounter; + uint16 txStatControl; + uint16 txRetryLimit; + + uint8 listenCount; + uint8 listenInterval; + uint10 beaconInterval; + uint2 preamble; + uint16 preBeacon; + uint11 random; + + struct { + uint1 enable; + uint1 enableIrq; + uint1 enableTxMP; + uint64 count; + uint64 compare; + } timer; + + uint2 config0d4; + uint12 config0d8; + uint16 config0da; + uint5 config0ecl; + uint6 config0ech; + + uint9 config120l; + uint1 config120h; + uint16 config122; + uint16 config124; + uint16 config128; + uint12 config130; + uint12 config132l; + uint1 config132h; + uint16 configBeaconCount; + + uint16 config140; + uint16 config142; + uint8 config144; + uint8 config146; + uint8 config148; + uint8 config14a; + uint16 config14c; + + uint6 config150l; + uint8 config150h; + uint7 config154l; + uint1 config154m; + uint4 config154h; + + uint2 reg1a0l; + uint2 reg1a0m; + uint1 reg1a0n; + uint1 reg1a0h; + uint2 reg1a2; + uint16 reg1a4; + + struct { + uint16 enable, counterEnable, oflowEnable; + uint16 flags, counterFlags, oflowFlags; + } interrupt; + + struct { + uint8 reg1b0; + uint16 reg1b2; + uint16 reg1b4; + uint16 reg1b6; + uint8 reg1b8; + uint8 reg1ba; + uint16 reg1bc; + uint16 reg1be; + uint16 txErrors; + uint16 rxPackets; + uint8 mpErrors[16]; + } stats; + + struct { + uint4 txIdle; + uint2 wakeRequest; + uint1 wakePending; + uint1 sleeping; + } pm; + + // Baseband serial interface + struct { + uint16 header; // 01rw0000 aaaaaaaa (r/w, address) + uint8 read, write; // data sent and received + uint4 powerl; + uint1 powerh; + uint1 mode8, modeE; + uint1 busy; + uint1 clock; + + uint8 time; + Event event; + + uint8 regs[0x69]; + } bb; + + // RF serial interface + struct { + uint32 data; // r aaaaa dd dddddddd dddddddd (r/w, address, data) + uint6 length; // should be 24 bits + uint1 type; // should be 0 + uint1 reserved; + uint1 busy; + + uint8 time; + Event event; + + uint18 regs[0x20]; + } rf; +}; + +extern WIFI wifi; \ No newline at end of file diff --git a/bsnes/phoenix/Makefile b/bsnes/phoenix/Makefile old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/core/core.cpp b/bsnes/phoenix/core/core.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/core/core.hpp b/bsnes/phoenix/core/core.hpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/core/keyboard.hpp b/bsnes/phoenix/core/keyboard.hpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/core/layout/fixed-layout.cpp b/bsnes/phoenix/core/layout/fixed-layout.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/core/layout/fixed-layout.hpp b/bsnes/phoenix/core/layout/fixed-layout.hpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/core/layout/horizontal-layout.cpp b/bsnes/phoenix/core/layout/horizontal-layout.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/core/layout/horizontal-layout.hpp b/bsnes/phoenix/core/layout/horizontal-layout.hpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/core/layout/vertical-layout.cpp b/bsnes/phoenix/core/layout/vertical-layout.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/core/layout/vertical-layout.hpp b/bsnes/phoenix/core/layout/vertical-layout.hpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/core/state.hpp b/bsnes/phoenix/core/state.hpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/action/action.cpp b/bsnes/phoenix/gtk/action/action.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/action/check-item.cpp b/bsnes/phoenix/gtk/action/check-item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/action/item.cpp b/bsnes/phoenix/gtk/action/item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/action/menu.cpp b/bsnes/phoenix/gtk/action/menu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/action/radio-item.cpp b/bsnes/phoenix/gtk/action/radio-item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/action/separator.cpp b/bsnes/phoenix/gtk/action/separator.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/desktop.cpp b/bsnes/phoenix/gtk/desktop.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/dialog-window.cpp b/bsnes/phoenix/gtk/dialog-window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/font.cpp b/bsnes/phoenix/gtk/font.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/keyboard.cpp b/bsnes/phoenix/gtk/keyboard.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/message-window.cpp b/bsnes/phoenix/gtk/message-window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/mouse.cpp b/bsnes/phoenix/gtk/mouse.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/platform.cpp b/bsnes/phoenix/gtk/platform.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/platform.hpp b/bsnes/phoenix/gtk/platform.hpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/settings.cpp b/bsnes/phoenix/gtk/settings.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/timer.cpp b/bsnes/phoenix/gtk/timer.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/utility.cpp b/bsnes/phoenix/gtk/utility.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/button.cpp b/bsnes/phoenix/gtk/widget/button.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/canvas.cpp b/bsnes/phoenix/gtk/widget/canvas.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/check-box.cpp b/bsnes/phoenix/gtk/widget/check-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/combo-box.cpp b/bsnes/phoenix/gtk/widget/combo-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/hex-edit.cpp b/bsnes/phoenix/gtk/widget/hex-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/horizontal-scroll-bar.cpp b/bsnes/phoenix/gtk/widget/horizontal-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/horizontal-slider.cpp b/bsnes/phoenix/gtk/widget/horizontal-slider.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/label.cpp b/bsnes/phoenix/gtk/widget/label.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/line-edit.cpp b/bsnes/phoenix/gtk/widget/line-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/list-view.cpp b/bsnes/phoenix/gtk/widget/list-view.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/progress-bar.cpp b/bsnes/phoenix/gtk/widget/progress-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/radio-box.cpp b/bsnes/phoenix/gtk/widget/radio-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/text-edit.cpp b/bsnes/phoenix/gtk/widget/text-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/vertical-scroll-bar.cpp b/bsnes/phoenix/gtk/widget/vertical-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/vertical-slider.cpp b/bsnes/phoenix/gtk/widget/vertical-slider.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/viewport.cpp b/bsnes/phoenix/gtk/widget/viewport.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/widget/widget.cpp b/bsnes/phoenix/gtk/widget/widget.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/gtk/window.cpp b/bsnes/phoenix/gtk/window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/phoenix.cpp b/bsnes/phoenix/phoenix.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/phoenix.hpp b/bsnes/phoenix/phoenix.hpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/action/action.cpp b/bsnes/phoenix/qt/action/action.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/action/check-item.cpp b/bsnes/phoenix/qt/action/check-item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/action/item.cpp b/bsnes/phoenix/qt/action/item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/action/menu.cpp b/bsnes/phoenix/qt/action/menu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/action/radio-item.cpp b/bsnes/phoenix/qt/action/radio-item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/action/separator.cpp b/bsnes/phoenix/qt/action/separator.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/desktop.cpp b/bsnes/phoenix/qt/desktop.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/dialog-window.cpp b/bsnes/phoenix/qt/dialog-window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/font.cpp b/bsnes/phoenix/qt/font.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/keyboard.cpp b/bsnes/phoenix/qt/keyboard.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/message-window.cpp b/bsnes/phoenix/qt/message-window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/mouse.cpp b/bsnes/phoenix/qt/mouse.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/platform.cpp b/bsnes/phoenix/qt/platform.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/platform.moc b/bsnes/phoenix/qt/platform.moc old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/platform.moc.hpp b/bsnes/phoenix/qt/platform.moc.hpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/settings.cpp b/bsnes/phoenix/qt/settings.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/timer.cpp b/bsnes/phoenix/qt/timer.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/utility.cpp b/bsnes/phoenix/qt/utility.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/button.cpp b/bsnes/phoenix/qt/widget/button.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/canvas.cpp b/bsnes/phoenix/qt/widget/canvas.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/check-box.cpp b/bsnes/phoenix/qt/widget/check-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/combo-box.cpp b/bsnes/phoenix/qt/widget/combo-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/hex-edit.cpp b/bsnes/phoenix/qt/widget/hex-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/horizontal-scroll-bar.cpp b/bsnes/phoenix/qt/widget/horizontal-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/horizontal-slider.cpp b/bsnes/phoenix/qt/widget/horizontal-slider.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/label.cpp b/bsnes/phoenix/qt/widget/label.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/line-edit.cpp b/bsnes/phoenix/qt/widget/line-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/list-view.cpp b/bsnes/phoenix/qt/widget/list-view.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/progress-bar.cpp b/bsnes/phoenix/qt/widget/progress-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/radio-box.cpp b/bsnes/phoenix/qt/widget/radio-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/text-edit.cpp b/bsnes/phoenix/qt/widget/text-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/vertical-scroll-bar.cpp b/bsnes/phoenix/qt/widget/vertical-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/vertical-slider.cpp b/bsnes/phoenix/qt/widget/vertical-slider.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/viewport.cpp b/bsnes/phoenix/qt/widget/viewport.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/widget/widget.cpp b/bsnes/phoenix/qt/widget/widget.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/qt/window.cpp b/bsnes/phoenix/qt/window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/action/action.cpp b/bsnes/phoenix/reference/action/action.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/action/check-item.cpp b/bsnes/phoenix/reference/action/check-item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/action/item.cpp b/bsnes/phoenix/reference/action/item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/action/menu.cpp b/bsnes/phoenix/reference/action/menu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/action/radio-item.cpp b/bsnes/phoenix/reference/action/radio-item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/action/separator.cpp b/bsnes/phoenix/reference/action/separator.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/desktop.cpp b/bsnes/phoenix/reference/desktop.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/dialog-window.cpp b/bsnes/phoenix/reference/dialog-window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/font.cpp b/bsnes/phoenix/reference/font.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/keyboard.cpp b/bsnes/phoenix/reference/keyboard.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/message-window.cpp b/bsnes/phoenix/reference/message-window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/mouse.cpp b/bsnes/phoenix/reference/mouse.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/platform.cpp b/bsnes/phoenix/reference/platform.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/platform.hpp b/bsnes/phoenix/reference/platform.hpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/timer.cpp b/bsnes/phoenix/reference/timer.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/button.cpp b/bsnes/phoenix/reference/widget/button.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/canvas.cpp b/bsnes/phoenix/reference/widget/canvas.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/check-box.cpp b/bsnes/phoenix/reference/widget/check-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/combo-box.cpp b/bsnes/phoenix/reference/widget/combo-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/hex-edit.cpp b/bsnes/phoenix/reference/widget/hex-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/horizontal-scroll-bar.cpp b/bsnes/phoenix/reference/widget/horizontal-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/horizontal-slider.cpp b/bsnes/phoenix/reference/widget/horizontal-slider.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/label.cpp b/bsnes/phoenix/reference/widget/label.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/line-edit.cpp b/bsnes/phoenix/reference/widget/line-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/list-view.cpp b/bsnes/phoenix/reference/widget/list-view.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/progress-bar.cpp b/bsnes/phoenix/reference/widget/progress-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/radio-box.cpp b/bsnes/phoenix/reference/widget/radio-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/text-edit.cpp b/bsnes/phoenix/reference/widget/text-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/vertical-scroll-bar.cpp b/bsnes/phoenix/reference/widget/vertical-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/vertical-slider.cpp b/bsnes/phoenix/reference/widget/vertical-slider.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/viewport.cpp b/bsnes/phoenix/reference/widget/viewport.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/widget/widget.cpp b/bsnes/phoenix/reference/widget/widget.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/reference/window.cpp b/bsnes/phoenix/reference/window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/sync.sh b/bsnes/phoenix/sync.sh old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/action/action.cpp b/bsnes/phoenix/windows/action/action.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/action/check-item.cpp b/bsnes/phoenix/windows/action/check-item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/action/item.cpp b/bsnes/phoenix/windows/action/item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/action/menu.cpp b/bsnes/phoenix/windows/action/menu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/action/radio-item.cpp b/bsnes/phoenix/windows/action/radio-item.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/action/separator.cpp b/bsnes/phoenix/windows/action/separator.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/desktop.cpp b/bsnes/phoenix/windows/desktop.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/dialog-window.cpp b/bsnes/phoenix/windows/dialog-window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/font.cpp b/bsnes/phoenix/windows/font.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/keyboard.cpp b/bsnes/phoenix/windows/keyboard.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/message-window.cpp b/bsnes/phoenix/windows/message-window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/mouse.cpp b/bsnes/phoenix/windows/mouse.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/object.cpp b/bsnes/phoenix/windows/object.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/phoenix.Manifest b/bsnes/phoenix/windows/phoenix.Manifest old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/phoenix.rc b/bsnes/phoenix/windows/phoenix.rc old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/platform.cpp b/bsnes/phoenix/windows/platform.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/platform.hpp b/bsnes/phoenix/windows/platform.hpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/settings.cpp b/bsnes/phoenix/windows/settings.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/timer.cpp b/bsnes/phoenix/windows/timer.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/utility.cpp b/bsnes/phoenix/windows/utility.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/button.cpp b/bsnes/phoenix/windows/widget/button.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/canvas.cpp b/bsnes/phoenix/windows/widget/canvas.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/check-box.cpp b/bsnes/phoenix/windows/widget/check-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/combo-box.cpp b/bsnes/phoenix/windows/widget/combo-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/hex-edit.cpp b/bsnes/phoenix/windows/widget/hex-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/horizontal-scroll-bar.cpp b/bsnes/phoenix/windows/widget/horizontal-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/horizontal-slider.cpp b/bsnes/phoenix/windows/widget/horizontal-slider.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/label.cpp b/bsnes/phoenix/windows/widget/label.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/line-edit.cpp b/bsnes/phoenix/windows/widget/line-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/list-view.cpp b/bsnes/phoenix/windows/widget/list-view.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/progress-bar.cpp b/bsnes/phoenix/windows/widget/progress-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/radio-box.cpp b/bsnes/phoenix/windows/widget/radio-box.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/text-edit.cpp b/bsnes/phoenix/windows/widget/text-edit.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/vertical-scroll-bar.cpp b/bsnes/phoenix/windows/widget/vertical-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/vertical-slider.cpp b/bsnes/phoenix/windows/widget/vertical-slider.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/viewport.cpp b/bsnes/phoenix/windows/widget/viewport.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/widget/widget.cpp b/bsnes/phoenix/windows/widget/widget.cpp old mode 100755 new mode 100644 diff --git a/bsnes/phoenix/windows/window.cpp b/bsnes/phoenix/windows/window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/Makefile b/bsnes/processor/Makefile old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/algorithms.cpp b/bsnes/processor/arm/algorithms.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/arm.cpp b/bsnes/processor/arm/arm.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/arm.hpp b/bsnes/processor/arm/arm.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/disassembler.cpp b/bsnes/processor/arm/disassembler.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/disassembler.hpp b/bsnes/processor/arm/disassembler.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/instructions-arm.cpp b/bsnes/processor/arm/instructions-arm.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/instructions-arm.hpp b/bsnes/processor/arm/instructions-arm.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/instructions-thumb.cpp b/bsnes/processor/arm/instructions-thumb.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/instructions-thumb.hpp b/bsnes/processor/arm/instructions-thumb.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/registers.cpp b/bsnes/processor/arm/registers.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/registers.hpp b/bsnes/processor/arm/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/arm/serialization.cpp b/bsnes/processor/arm/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/gsu/gsu.cpp b/bsnes/processor/gsu/gsu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/gsu/gsu.hpp b/bsnes/processor/gsu/gsu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/gsu/instructions.cpp b/bsnes/processor/gsu/instructions.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/gsu/registers.hpp b/bsnes/processor/gsu/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/gsu/serialization.cpp b/bsnes/processor/gsu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/gsu/table.cpp b/bsnes/processor/gsu/table.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/hg51b/hg51b.cpp b/bsnes/processor/hg51b/hg51b.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/hg51b/hg51b.hpp b/bsnes/processor/hg51b/hg51b.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/hg51b/instructions.cpp b/bsnes/processor/hg51b/instructions.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/hg51b/registers.cpp b/bsnes/processor/hg51b/registers.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/hg51b/registers.hpp b/bsnes/processor/hg51b/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/hg51b/serialization.cpp b/bsnes/processor/hg51b/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/lr35902/disassembler.cpp b/bsnes/processor/lr35902/disassembler.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/lr35902/instructions.cpp b/bsnes/processor/lr35902/instructions.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/lr35902/lr35902.cpp b/bsnes/processor/lr35902/lr35902.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/lr35902/lr35902.hpp b/bsnes/processor/lr35902/lr35902.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/lr35902/registers.hpp b/bsnes/processor/lr35902/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/lr35902/serialization.cpp b/bsnes/processor/lr35902/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/processor.hpp b/bsnes/processor/processor.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r6502/disassembler.cpp b/bsnes/processor/r6502/disassembler.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r6502/instructions.cpp b/bsnes/processor/r6502/instructions.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r6502/memory.cpp b/bsnes/processor/r6502/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r6502/r6502.cpp b/bsnes/processor/r6502/r6502.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r6502/r6502.hpp b/bsnes/processor/r6502/r6502.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r6502/registers.hpp b/bsnes/processor/r6502/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r6502/serialization.cpp b/bsnes/processor/r6502/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/algorithms.cpp b/bsnes/processor/r65816/algorithms.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/disassembler.cpp b/bsnes/processor/r65816/disassembler.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/disassembler.hpp b/bsnes/processor/r65816/disassembler.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/memory.hpp b/bsnes/processor/r65816/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/opcode_misc.cpp b/bsnes/processor/r65816/opcode_misc.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/opcode_pc.cpp b/bsnes/processor/r65816/opcode_pc.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/opcode_read.cpp b/bsnes/processor/r65816/opcode_read.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/opcode_rmw.cpp b/bsnes/processor/r65816/opcode_rmw.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/opcode_write.cpp b/bsnes/processor/r65816/opcode_write.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/r65816.cpp b/bsnes/processor/r65816/r65816.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/r65816.hpp b/bsnes/processor/r65816/r65816.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/registers.hpp b/bsnes/processor/r65816/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/serialization.cpp b/bsnes/processor/r65816/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/r65816/table.cpp b/bsnes/processor/r65816/table.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/spc700/algorithms.cpp b/bsnes/processor/spc700/algorithms.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/spc700/disassembler.cpp b/bsnes/processor/spc700/disassembler.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/spc700/instructions.cpp b/bsnes/processor/spc700/instructions.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/spc700/memory.hpp b/bsnes/processor/spc700/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/spc700/registers.hpp b/bsnes/processor/spc700/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/spc700/serialization.cpp b/bsnes/processor/spc700/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/spc700/spc700.cpp b/bsnes/processor/spc700/spc700.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/spc700/spc700.hpp b/bsnes/processor/spc700/spc700.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/upd96050/disassembler.cpp b/bsnes/processor/upd96050/disassembler.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/upd96050/instructions.cpp b/bsnes/processor/upd96050/instructions.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/upd96050/memory.cpp b/bsnes/processor/upd96050/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/upd96050/registers.hpp b/bsnes/processor/upd96050/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/upd96050/serialization.cpp b/bsnes/processor/upd96050/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/upd96050/upd96050.cpp b/bsnes/processor/upd96050/upd96050.cpp old mode 100755 new mode 100644 diff --git a/bsnes/processor/upd96050/upd96050.hpp b/bsnes/processor/upd96050/upd96050.hpp old mode 100755 new mode 100644 diff --git a/bsnes/profile/BS-X Satellaview.sfc/manifest.xml b/bsnes/profile/BS-X Satellaview.sfc/manifest.xml old mode 100755 new mode 100644 diff --git a/bsnes/profile/Famicom.sys/manifest.xml b/bsnes/profile/Famicom.sys/manifest.xml old mode 100755 new mode 100644 diff --git a/bsnes/profile/Game Boy Advance.sys/manifest.xml b/bsnes/profile/Game Boy Advance.sys/manifest.xml old mode 100755 new mode 100644 diff --git a/bsnes/profile/Game Boy Color.sys/boot.rom b/bsnes/profile/Game Boy Color.sys/boot.rom old mode 100755 new mode 100644 diff --git a/bsnes/profile/Game Boy Color.sys/manifest.xml b/bsnes/profile/Game Boy Color.sys/manifest.xml old mode 100755 new mode 100644 diff --git a/bsnes/profile/Game Boy.sys/boot.rom b/bsnes/profile/Game Boy.sys/boot.rom old mode 100755 new mode 100644 diff --git a/bsnes/profile/Game Boy.sys/manifest.xml b/bsnes/profile/Game Boy.sys/manifest.xml old mode 100755 new mode 100644 diff --git a/bsnes/profile/Nintendo DS.sys/manifest.xml b/bsnes/profile/Nintendo DS.sys/manifest.xml new file mode 100644 index 00000000..732887a3 --- /dev/null +++ b/bsnes/profile/Nintendo DS.sys/manifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/bsnes/profile/Sufami Turbo.sfc/manifest.xml b/bsnes/profile/Sufami Turbo.sfc/manifest.xml old mode 100755 new mode 100644 diff --git a/bsnes/profile/Super Famicom.sys/manifest.xml b/bsnes/profile/Super Famicom.sys/manifest.xml old mode 100755 new mode 100644 diff --git a/bsnes/profile/Super Famicom.sys/spc700.rom b/bsnes/profile/Super Famicom.sys/spc700.rom old mode 100755 new mode 100644 diff --git a/bsnes/profile/Super Game Boy.sfc/boot.rom b/bsnes/profile/Super Game Boy.sfc/boot.rom old mode 100755 new mode 100644 diff --git a/bsnes/profile/Super Game Boy.sfc/manifest.xml b/bsnes/profile/Super Game Boy.sfc/manifest.xml old mode 100755 new mode 100644 diff --git a/bsnes/ruby/Makefile b/bsnes/ruby/Makefile old mode 100755 new mode 100644 diff --git a/bsnes/ruby/audio.hpp b/bsnes/ruby/audio.hpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/audio/alsa.cpp b/bsnes/ruby/audio/alsa.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/audio/ao.cpp b/bsnes/ruby/audio/ao.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/audio/directsound.cpp b/bsnes/ruby/audio/directsound.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/audio/openal.cpp b/bsnes/ruby/audio/openal.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/audio/oss.cpp b/bsnes/ruby/audio/oss.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/audio/pulseaudio.cpp b/bsnes/ruby/audio/pulseaudio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/audio/pulseaudiosimple.cpp b/bsnes/ruby/audio/pulseaudiosimple.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/audio/xaudio2.cpp b/bsnes/ruby/audio/xaudio2.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/audio/xaudio2.hpp b/bsnes/ruby/audio/xaudio2.hpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/input.hpp b/bsnes/ruby/input.hpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/input/carbon.cpp b/bsnes/ruby/input/carbon.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/input/directinput.cpp b/bsnes/ruby/input/directinput.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/input/rawinput.cpp b/bsnes/ruby/input/rawinput.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/input/sdl.cpp b/bsnes/ruby/input/sdl.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/input/x.cpp b/bsnes/ruby/input/x.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/input/xlibkeys.hpp b/bsnes/ruby/input/xlibkeys.hpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/ruby.cpp b/bsnes/ruby/ruby.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/ruby.hpp b/bsnes/ruby/ruby.hpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/ruby_impl.cpp b/bsnes/ruby/ruby_impl.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video.hpp b/bsnes/ruby/video.hpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video/direct3d.cpp b/bsnes/ruby/video/direct3d.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video/directdraw.cpp b/bsnes/ruby/video/directdraw.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video/gdi.cpp b/bsnes/ruby/video/gdi.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video/glx.cpp b/bsnes/ruby/video/glx.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video/opengl.hpp b/bsnes/ruby/video/opengl.hpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video/qtopengl.cpp b/bsnes/ruby/video/qtopengl.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video/qtraster.cpp b/bsnes/ruby/video/qtraster.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video/sdl.cpp b/bsnes/ruby/video/sdl.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video/wgl.cpp b/bsnes/ruby/video/wgl.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video/xshm.cpp b/bsnes/ruby/video/xshm.cpp old mode 100755 new mode 100644 diff --git a/bsnes/ruby/video/xv.cpp b/bsnes/ruby/video/xv.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/Makefile b/bsnes/sfc/Makefile old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/cpu/cpu.cpp b/bsnes/sfc/alt/cpu/cpu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/cpu/cpu.hpp b/bsnes/sfc/alt/cpu/cpu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/cpu/dma.cpp b/bsnes/sfc/alt/cpu/dma.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/cpu/memory.cpp b/bsnes/sfc/alt/cpu/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/cpu/mmio.cpp b/bsnes/sfc/alt/cpu/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/cpu/serialization.cpp b/bsnes/sfc/alt/cpu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/cpu/timing.cpp b/bsnes/sfc/alt/cpu/timing.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/dsp/SPC_DSP.cpp b/bsnes/sfc/alt/dsp/SPC_DSP.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/dsp/SPC_DSP.h b/bsnes/sfc/alt/dsp/SPC_DSP.h old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/dsp/blargg_common.h b/bsnes/sfc/alt/dsp/blargg_common.h old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/dsp/blargg_config.h b/bsnes/sfc/alt/dsp/blargg_config.h old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/dsp/blargg_endian.h b/bsnes/sfc/alt/dsp/blargg_endian.h old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/dsp/blargg_source.h b/bsnes/sfc/alt/dsp/blargg_source.h old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/dsp/dsp.cpp b/bsnes/sfc/alt/dsp/dsp.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/dsp/dsp.hpp b/bsnes/sfc/alt/dsp/dsp.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/dsp/serialization.cpp b/bsnes/sfc/alt/dsp/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/memory/memory.cpp b/bsnes/sfc/alt/ppu-compatibility/memory/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/memory/memory.hpp b/bsnes/sfc/alt/ppu-compatibility/memory/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/mmio/mmio.cpp b/bsnes/sfc/alt/ppu-compatibility/mmio/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/mmio/mmio.hpp b/bsnes/sfc/alt/ppu-compatibility/mmio/mmio.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/ppu.cpp b/bsnes/sfc/alt/ppu-compatibility/ppu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/ppu.hpp b/bsnes/sfc/alt/ppu-compatibility/ppu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/render/addsub.cpp b/bsnes/sfc/alt/ppu-compatibility/render/addsub.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/render/bg.cpp b/bsnes/sfc/alt/ppu-compatibility/render/bg.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/render/cache.cpp b/bsnes/sfc/alt/ppu-compatibility/render/cache.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/render/line.cpp b/bsnes/sfc/alt/ppu-compatibility/render/line.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/render/mode7.cpp b/bsnes/sfc/alt/ppu-compatibility/render/mode7.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/render/oam.cpp b/bsnes/sfc/alt/ppu-compatibility/render/oam.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/render/render.cpp b/bsnes/sfc/alt/ppu-compatibility/render/render.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/render/render.hpp b/bsnes/sfc/alt/ppu-compatibility/render/render.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/render/windows.cpp b/bsnes/sfc/alt/ppu-compatibility/render/windows.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-compatibility/serialization.cpp b/bsnes/sfc/alt/ppu-compatibility/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/background/background.cpp b/bsnes/sfc/alt/ppu-performance/background/background.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/background/background.hpp b/bsnes/sfc/alt/ppu-performance/background/background.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/background/mode7.cpp b/bsnes/sfc/alt/ppu-performance/background/mode7.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/cache/cache.cpp b/bsnes/sfc/alt/ppu-performance/cache/cache.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/cache/cache.hpp b/bsnes/sfc/alt/ppu-performance/cache/cache.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/mmio/mmio.cpp b/bsnes/sfc/alt/ppu-performance/mmio/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/mmio/mmio.hpp b/bsnes/sfc/alt/ppu-performance/mmio/mmio.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/ppu.cpp b/bsnes/sfc/alt/ppu-performance/ppu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/ppu.hpp b/bsnes/sfc/alt/ppu-performance/ppu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/screen/screen.cpp b/bsnes/sfc/alt/ppu-performance/screen/screen.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/screen/screen.hpp b/bsnes/sfc/alt/ppu-performance/screen/screen.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/serialization.cpp b/bsnes/sfc/alt/ppu-performance/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/sprite/sprite.cpp b/bsnes/sfc/alt/ppu-performance/sprite/sprite.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/sprite/sprite.hpp b/bsnes/sfc/alt/ppu-performance/sprite/sprite.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/window/window.cpp b/bsnes/sfc/alt/ppu-performance/window/window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/ppu-performance/window/window.hpp b/bsnes/sfc/alt/ppu-performance/window/window.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/algorithms.cpp b/bsnes/sfc/alt/smp/algorithms.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core.cpp b/bsnes/sfc/alt/smp/core.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/cc.sh b/bsnes/sfc/alt/smp/core/cc.sh old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/generate.cpp b/bsnes/sfc/alt/smp/core/generate.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/op_misc.b b/bsnes/sfc/alt/smp/core/op_misc.b old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/op_misc.cpp b/bsnes/sfc/alt/smp/core/op_misc.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/op_mov.b b/bsnes/sfc/alt/smp/core/op_mov.b old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/op_mov.cpp b/bsnes/sfc/alt/smp/core/op_mov.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/op_pc.b b/bsnes/sfc/alt/smp/core/op_pc.b old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/op_pc.cpp b/bsnes/sfc/alt/smp/core/op_pc.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/op_read.b b/bsnes/sfc/alt/smp/core/op_read.b old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/op_read.cpp b/bsnes/sfc/alt/smp/core/op_read.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/op_rmw.b b/bsnes/sfc/alt/smp/core/op_rmw.b old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/op_rmw.cpp b/bsnes/sfc/alt/smp/core/op_rmw.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/opcycle_misc.cpp b/bsnes/sfc/alt/smp/core/opcycle_misc.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/opcycle_mov.cpp b/bsnes/sfc/alt/smp/core/opcycle_mov.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/opcycle_pc.cpp b/bsnes/sfc/alt/smp/core/opcycle_pc.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/opcycle_read.cpp b/bsnes/sfc/alt/smp/core/opcycle_read.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/core/opcycle_rmw.cpp b/bsnes/sfc/alt/smp/core/opcycle_rmw.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/disassembler.cpp b/bsnes/sfc/alt/smp/disassembler.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/memory.cpp b/bsnes/sfc/alt/smp/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/smp.cpp b/bsnes/sfc/alt/smp/smp.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/smp.hpp b/bsnes/sfc/alt/smp/smp.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/alt/smp/timing.cpp b/bsnes/sfc/alt/smp/timing.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cartridge/cartridge.cpp b/bsnes/sfc/cartridge/cartridge.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cartridge/cartridge.hpp b/bsnes/sfc/cartridge/cartridge.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cartridge/markup.cpp b/bsnes/sfc/cartridge/markup.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cartridge/serialization.cpp b/bsnes/sfc/cartridge/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cheat/cheat.cpp b/bsnes/sfc/cheat/cheat.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cheat/cheat.hpp b/bsnes/sfc/cheat/cheat.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/armdsp/armdsp.cpp b/bsnes/sfc/chip/armdsp/armdsp.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/armdsp/armdsp.hpp b/bsnes/sfc/chip/armdsp/armdsp.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/armdsp/memory.cpp b/bsnes/sfc/chip/armdsp/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/armdsp/registers.hpp b/bsnes/sfc/chip/armdsp/registers.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/armdsp/serialization.cpp b/bsnes/sfc/chip/armdsp/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/bsx/bsx.cpp b/bsnes/sfc/chip/bsx/bsx.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/bsx/bsx.hpp b/bsnes/sfc/chip/bsx/bsx.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/bsx/cartridge/cartridge.cpp b/bsnes/sfc/chip/bsx/cartridge/cartridge.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/bsx/cartridge/cartridge.hpp b/bsnes/sfc/chip/bsx/cartridge/cartridge.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/bsx/cartridge/serialization.cpp b/bsnes/sfc/chip/bsx/cartridge/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/bsx/flash/flash.cpp b/bsnes/sfc/chip/bsx/flash/flash.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/bsx/flash/flash.hpp b/bsnes/sfc/chip/bsx/flash/flash.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/bsx/satellaview/satellaview.cpp b/bsnes/sfc/chip/bsx/satellaview/satellaview.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/bsx/satellaview/satellaview.hpp b/bsnes/sfc/chip/bsx/satellaview/satellaview.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/chip.hpp b/bsnes/sfc/chip/chip.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/epsonrtc/epsonrtc.cpp b/bsnes/sfc/chip/epsonrtc/epsonrtc.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/epsonrtc/epsonrtc.hpp b/bsnes/sfc/chip/epsonrtc/epsonrtc.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/epsonrtc/memory.cpp b/bsnes/sfc/chip/epsonrtc/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/epsonrtc/serialization.cpp b/bsnes/sfc/chip/epsonrtc/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/epsonrtc/time.cpp b/bsnes/sfc/chip/epsonrtc/time.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/hitachidsp/hitachidsp.cpp b/bsnes/sfc/chip/hitachidsp/hitachidsp.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/hitachidsp/hitachidsp.hpp b/bsnes/sfc/chip/hitachidsp/hitachidsp.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/hitachidsp/memory.cpp b/bsnes/sfc/chip/hitachidsp/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/hitachidsp/mmio.hpp b/bsnes/sfc/chip/hitachidsp/mmio.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/hitachidsp/serialization.cpp b/bsnes/sfc/chip/hitachidsp/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/icd2/icd2.cpp b/bsnes/sfc/chip/icd2/icd2.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/icd2/icd2.hpp b/bsnes/sfc/chip/icd2/icd2.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/icd2/interface/interface.cpp b/bsnes/sfc/chip/icd2/interface/interface.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/icd2/interface/interface.hpp b/bsnes/sfc/chip/icd2/interface/interface.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/icd2/mmio/mmio.cpp b/bsnes/sfc/chip/icd2/mmio/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/icd2/mmio/mmio.hpp b/bsnes/sfc/chip/icd2/mmio/mmio.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/icd2/serialization.cpp b/bsnes/sfc/chip/icd2/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/msu1/msu1.cpp b/bsnes/sfc/chip/msu1/msu1.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/msu1/msu1.hpp b/bsnes/sfc/chip/msu1/msu1.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/msu1/serialization.cpp b/bsnes/sfc/chip/msu1/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/necdsp/necdsp.cpp b/bsnes/sfc/chip/necdsp/necdsp.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/necdsp/necdsp.hpp b/bsnes/sfc/chip/necdsp/necdsp.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/necdsp/serialization.cpp b/bsnes/sfc/chip/necdsp/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/nss/nss.cpp b/bsnes/sfc/chip/nss/nss.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/nss/nss.hpp b/bsnes/sfc/chip/nss/nss.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/obc1/obc1.cpp b/bsnes/sfc/chip/obc1/obc1.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/obc1/obc1.hpp b/bsnes/sfc/chip/obc1/obc1.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/obc1/serialization.cpp b/bsnes/sfc/chip/obc1/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sa1/bus/bus.cpp b/bsnes/sfc/chip/sa1/bus/bus.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sa1/bus/bus.hpp b/bsnes/sfc/chip/sa1/bus/bus.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sa1/dma/dma.cpp b/bsnes/sfc/chip/sa1/dma/dma.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sa1/dma/dma.hpp b/bsnes/sfc/chip/sa1/dma/dma.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sa1/memory/memory.cpp b/bsnes/sfc/chip/sa1/memory/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sa1/memory/memory.hpp b/bsnes/sfc/chip/sa1/memory/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sa1/mmio/mmio.cpp b/bsnes/sfc/chip/sa1/mmio/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sa1/mmio/mmio.hpp b/bsnes/sfc/chip/sa1/mmio/mmio.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sa1/sa1.cpp b/bsnes/sfc/chip/sa1/sa1.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sa1/sa1.hpp b/bsnes/sfc/chip/sa1/sa1.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sa1/serialization.cpp b/bsnes/sfc/chip/sa1/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sdd1/decomp.cpp b/bsnes/sfc/chip/sdd1/decomp.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sdd1/decomp.hpp b/bsnes/sfc/chip/sdd1/decomp.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sdd1/sdd1.cpp b/bsnes/sfc/chip/sdd1/sdd1.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sdd1/sdd1.hpp b/bsnes/sfc/chip/sdd1/sdd1.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sdd1/serialization.cpp b/bsnes/sfc/chip/sdd1/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sharprtc/memory.cpp b/bsnes/sfc/chip/sharprtc/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sharprtc/serialization.cpp b/bsnes/sfc/chip/sharprtc/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sharprtc/sharprtc.cpp b/bsnes/sfc/chip/sharprtc/sharprtc.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sharprtc/sharprtc.hpp b/bsnes/sfc/chip/sharprtc/sharprtc.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sharprtc/time.cpp b/bsnes/sfc/chip/sharprtc/time.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/spc7110/alu.cpp b/bsnes/sfc/chip/spc7110/alu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/spc7110/data.cpp b/bsnes/sfc/chip/spc7110/data.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/spc7110/dcu.cpp b/bsnes/sfc/chip/spc7110/dcu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/spc7110/decompressor.cpp b/bsnes/sfc/chip/spc7110/decompressor.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/spc7110/serialization.cpp b/bsnes/sfc/chip/spc7110/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/spc7110/spc7110.cpp b/bsnes/sfc/chip/spc7110/spc7110.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/spc7110/spc7110.hpp b/bsnes/sfc/chip/spc7110/spc7110.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sufamiturbo/serialization.cpp b/bsnes/sfc/chip/sufamiturbo/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sufamiturbo/sufamiturbo.cpp b/bsnes/sfc/chip/sufamiturbo/sufamiturbo.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/sufamiturbo/sufamiturbo.hpp b/bsnes/sfc/chip/sufamiturbo/sufamiturbo.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/bus/bus.cpp b/bsnes/sfc/chip/superfx/bus/bus.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/bus/bus.hpp b/bsnes/sfc/chip/superfx/bus/bus.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/core/core.cpp b/bsnes/sfc/chip/superfx/core/core.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/core/core.hpp b/bsnes/sfc/chip/superfx/core/core.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/disasm/disasm.cpp b/bsnes/sfc/chip/superfx/disasm/disasm.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/disasm/disasm.hpp b/bsnes/sfc/chip/superfx/disasm/disasm.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/memory/memory.cpp b/bsnes/sfc/chip/superfx/memory/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/memory/memory.hpp b/bsnes/sfc/chip/superfx/memory/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/mmio/mmio.cpp b/bsnes/sfc/chip/superfx/mmio/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/mmio/mmio.hpp b/bsnes/sfc/chip/superfx/mmio/mmio.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/serialization.cpp b/bsnes/sfc/chip/superfx/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/superfx.cpp b/bsnes/sfc/chip/superfx/superfx.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/superfx.hpp b/bsnes/sfc/chip/superfx/superfx.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/timing/timing.cpp b/bsnes/sfc/chip/superfx/timing/timing.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/chip/superfx/timing/timing.hpp b/bsnes/sfc/chip/superfx/timing/timing.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/config/config.cpp b/bsnes/sfc/config/config.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/config/config.hpp b/bsnes/sfc/config/config.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/controller/controller.cpp b/bsnes/sfc/controller/controller.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/controller/controller.hpp b/bsnes/sfc/controller/controller.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/controller/gamepad/gamepad.cpp b/bsnes/sfc/controller/gamepad/gamepad.cpp old mode 100755 new mode 100644 index 23d838f9..e78f93d3 --- a/bsnes/sfc/controller/gamepad/gamepad.cpp +++ b/bsnes/sfc/controller/gamepad/gamepad.cpp @@ -2,21 +2,56 @@ uint2 Gamepad::data() { if(counter >= 16) return 1; - uint2 result = 0; - if(counter < 12) result = interface->inputPoll(port, (unsigned)Input::Device::Joypad, counter); - if(latched == 0) counter++; - return result; + if(latched == 1) return interface->inputPoll(port, (unsigned)Input::Device::Joypad, (unsigned)Input::JoypadID::B); + + //note: D-pad physically prevents up+down and left+right from being pressed at the same time + switch(counter++) { + case 0: return b; + case 1: return y; + case 2: return select; + case 3: return start; + case 4: return up & !down; + case 5: return down & !up; + case 6: return left & !right; + case 7: return right & !left; + case 8: return a; + case 9: return x; + case 10: return l; + case 11: return r; + } + + return 0; //12-15: signature } void Gamepad::latch(bool data) { if(latched == data) return; latched = data; counter = 0; + + if(latched == 0) { + unsigned id = (unsigned)Input::Device::Joypad; + b = interface->inputPoll(port, id, 0); + y = interface->inputPoll(port, id, 1); + select = interface->inputPoll(port, id, 2); + start = interface->inputPoll(port, id, 3); + up = interface->inputPoll(port, id, 4); + down = interface->inputPoll(port, id, 5); + left = interface->inputPoll(port, id, 6); + right = interface->inputPoll(port, id, 7); + a = interface->inputPoll(port, id, 8); + x = interface->inputPoll(port, id, 9); + l = interface->inputPoll(port, id, 10); + r = interface->inputPoll(port, id, 11); + } } Gamepad::Gamepad(bool port) : Controller(port) { latched = 0; counter = 0; + + b = y = select = start = 0; + up = down = left = right = 0; + a = x = l = r = 0; } #endif diff --git a/bsnes/sfc/controller/gamepad/gamepad.hpp b/bsnes/sfc/controller/gamepad/gamepad.hpp old mode 100755 new mode 100644 index c5ca69ca..9a12cebf --- a/bsnes/sfc/controller/gamepad/gamepad.hpp +++ b/bsnes/sfc/controller/gamepad/gamepad.hpp @@ -6,4 +6,8 @@ struct Gamepad : Controller { private: bool latched; unsigned counter; + + bool b, y, select, start; + bool up, down, left, right; + bool a, x, l, r; }; diff --git a/bsnes/sfc/controller/justifier/justifier.cpp b/bsnes/sfc/controller/justifier/justifier.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/controller/justifier/justifier.hpp b/bsnes/sfc/controller/justifier/justifier.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/controller/mouse/mouse.cpp b/bsnes/sfc/controller/mouse/mouse.cpp old mode 100755 new mode 100644 index 9bc6f53d..83f647e6 --- a/bsnes/sfc/controller/mouse/mouse.cpp +++ b/bsnes/sfc/controller/mouse/mouse.cpp @@ -1,6 +1,11 @@ #ifdef CONTROLLER_CPP uint2 Mouse::data() { + if(latched == 1) { + speed = (speed + 1) % 3; + return 0; + } + if(counter >= 32) return 1; switch(counter++) { default: @@ -13,33 +18,33 @@ uint2 Mouse::data() { case 6: return 0; case 7: return 0; - case 8: return input.r; - case 9: return input.l; - case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused) - case 11: return 0; // || + case 8: return r; + case 9: return l; + case 10: return (speed >> 1) & 1; + case 11: return (speed >> 0) & 1; case 12: return 0; //signature case 13: return 0; // || case 14: return 0; // || case 15: return 1; // || - case 16: return input.dy; - case 17: return (input.y >> 6) & 1; - case 18: return (input.y >> 5) & 1; - case 19: return (input.y >> 4) & 1; - case 20: return (input.y >> 3) & 1; - case 21: return (input.y >> 2) & 1; - case 22: return (input.y >> 1) & 1; - case 23: return (input.y >> 0) & 1; + case 16: return dy; + case 17: return (y >> 6) & 1; + case 18: return (y >> 5) & 1; + case 19: return (y >> 4) & 1; + case 20: return (y >> 3) & 1; + case 21: return (y >> 2) & 1; + case 22: return (y >> 1) & 1; + case 23: return (y >> 0) & 1; - case 24: return input.dx; - case 25: return (input.x >> 6) & 1; - case 26: return (input.x >> 5) & 1; - case 27: return (input.x >> 4) & 1; - case 28: return (input.x >> 3) & 1; - case 29: return (input.x >> 2) & 1; - case 30: return (input.x >> 1) & 1; - case 31: return (input.x >> 0) & 1; + case 24: return dx; + case 25: return (x >> 6) & 1; + case 26: return (x >> 5) & 1; + case 27: return (x >> 4) & 1; + case 28: return (x >> 3) & 1; + case 29: return (x >> 2) & 1; + case 30: return (x >> 1) & 1; + case 31: return (x >> 0) & 1; } } @@ -48,31 +53,38 @@ void Mouse::latch(bool data) { latched = data; counter = 0; - input.x = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right - input.y = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down - input.l = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::Left ); - input.r = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::Right); + x = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right + y = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down + l = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::Left ); + r = interface->inputPoll(port, (unsigned)Input::Device::Mouse, (unsigned)Input::MouseID::Right); - input.dx = input.x < 0; //0 = right, 1 = left - input.dy = input.y < 0; //0 = down, 1 = up + dx = x < 0; //0 = right, 1 = left + dy = y < 0; //0 = down, 1 = up - if(input.x < 0) input.x = -input.x; //abs(position_x) - if(input.y < 0) input.y = -input.y; //abs(position_y) + if(x < 0) x = -x; //abs(position_x) + if(y < 0) y = -y; //abs(position_y) - input.x = min(127, input.x); - input.y = min(127, input.y); + double multiplier = 1.0; + if(speed == 1) multiplier = 1.5; + if(speed == 2) multiplier = 2.0; + x = (double)x * multiplier; + y = (double)y * multiplier; + + x = min(127, x); + y = min(127, y); } Mouse::Mouse(bool port) : Controller(port) { latched = 0; counter = 0; - input.x = 0; - input.y = 0; - input.dx = 0; - input.dy = 0; - input.l = 0; - input.r = 0; + speed = 0; + x = 0; + y = 0; + dx = 0; + dy = 0; + l = 0; + r = 0; } #endif diff --git a/bsnes/sfc/controller/mouse/mouse.hpp b/bsnes/sfc/controller/mouse/mouse.hpp old mode 100755 new mode 100644 index cc5871b0..2ecd9c3f --- a/bsnes/sfc/controller/mouse/mouse.hpp +++ b/bsnes/sfc/controller/mouse/mouse.hpp @@ -7,12 +7,11 @@ private: bool latched; unsigned counter; - struct MouseInput { - signed x; //x-coordinate - signed y; //y-coordinate - bool dx; //x-direction - bool dy; //y-direction - bool l; //left button - bool r; //right button - } input; + unsigned speed; //0 = slow, 1 = normal, 2 = fast + signed x; //x-coordinate + signed y; //y-coordinate + bool dx; //x-direction + bool dy; //y-direction + bool l; //left button + bool r; //right button }; diff --git a/bsnes/sfc/controller/multitap/multitap.cpp b/bsnes/sfc/controller/multitap/multitap.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/controller/multitap/multitap.hpp b/bsnes/sfc/controller/multitap/multitap.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/controller/superscope/superscope.cpp b/bsnes/sfc/controller/superscope/superscope.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/controller/superscope/superscope.hpp b/bsnes/sfc/controller/superscope/superscope.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/controller/usart/usart.cpp b/bsnes/sfc/controller/usart/usart.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/controller/usart/usart.hpp b/bsnes/sfc/controller/usart/usart.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/cpu.cpp b/bsnes/sfc/cpu/cpu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/cpu.hpp b/bsnes/sfc/cpu/cpu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/dma/dma.cpp b/bsnes/sfc/cpu/dma/dma.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/dma/dma.hpp b/bsnes/sfc/cpu/dma/dma.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/memory/memory.cpp b/bsnes/sfc/cpu/memory/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/memory/memory.hpp b/bsnes/sfc/cpu/memory/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/mmio/mmio.cpp b/bsnes/sfc/cpu/mmio/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/mmio/mmio.hpp b/bsnes/sfc/cpu/mmio/mmio.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/serialization.cpp b/bsnes/sfc/cpu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/timing/irq.cpp b/bsnes/sfc/cpu/timing/irq.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/timing/joypad.cpp b/bsnes/sfc/cpu/timing/joypad.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/timing/timing.cpp b/bsnes/sfc/cpu/timing/timing.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/cpu/timing/timing.hpp b/bsnes/sfc/cpu/timing/timing.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/dsp/brr.cpp b/bsnes/sfc/dsp/brr.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/dsp/counter.cpp b/bsnes/sfc/dsp/counter.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/dsp/dsp.cpp b/bsnes/sfc/dsp/dsp.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/dsp/dsp.hpp b/bsnes/sfc/dsp/dsp.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/dsp/echo.cpp b/bsnes/sfc/dsp/echo.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/dsp/envelope.cpp b/bsnes/sfc/dsp/envelope.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/dsp/gaussian.cpp b/bsnes/sfc/dsp/gaussian.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/dsp/misc.cpp b/bsnes/sfc/dsp/misc.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/dsp/moduloarray.hpp b/bsnes/sfc/dsp/moduloarray.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/dsp/serialization.cpp b/bsnes/sfc/dsp/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/dsp/voice.cpp b/bsnes/sfc/dsp/voice.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/interface/interface.cpp b/bsnes/sfc/interface/interface.cpp old mode 100755 new mode 100644 index dc4ebda6..61b51986 --- a/bsnes/sfc/interface/interface.cpp +++ b/bsnes/sfc/interface/interface.cpp @@ -285,7 +285,7 @@ void Interface::paletteUpdate() { bool Interface::tracerEnable(bool trace) { string pathname = {path(group(ID::ROM)), "debug/"}; - directory::create(pathname); + if(trace == true) directory::create(pathname); if(trace == true && !tracer.open()) { for(unsigned n = 0; n <= 999; n++) { diff --git a/bsnes/sfc/interface/interface.hpp b/bsnes/sfc/interface/interface.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/memory/memory-inline.hpp b/bsnes/sfc/memory/memory-inline.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/memory/memory.cpp b/bsnes/sfc/memory/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/memory/memory.hpp b/bsnes/sfc/memory/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/background/background.cpp b/bsnes/sfc/ppu/background/background.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/background/background.hpp b/bsnes/sfc/ppu/background/background.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/background/mode7.cpp b/bsnes/sfc/ppu/background/mode7.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/counter/counter-inline.hpp b/bsnes/sfc/ppu/counter/counter-inline.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/counter/counter.hpp b/bsnes/sfc/ppu/counter/counter.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/mmio/mmio.cpp b/bsnes/sfc/ppu/mmio/mmio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/mmio/mmio.hpp b/bsnes/sfc/ppu/mmio/mmio.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/ppu.cpp b/bsnes/sfc/ppu/ppu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/ppu.hpp b/bsnes/sfc/ppu/ppu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/screen/screen.cpp b/bsnes/sfc/ppu/screen/screen.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/screen/screen.hpp b/bsnes/sfc/ppu/screen/screen.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/serialization.cpp b/bsnes/sfc/ppu/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/sprite/list.cpp b/bsnes/sfc/ppu/sprite/list.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/sprite/sprite.cpp b/bsnes/sfc/ppu/sprite/sprite.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/sprite/sprite.hpp b/bsnes/sfc/ppu/sprite/sprite.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/window/window.cpp b/bsnes/sfc/ppu/window/window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/ppu/window/window.hpp b/bsnes/sfc/ppu/window/window.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/profile-accuracy.hpp b/bsnes/sfc/profile-accuracy.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/profile-compatibility.hpp b/bsnes/sfc/profile-compatibility.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/profile-performance.hpp b/bsnes/sfc/profile-performance.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/random/random.cpp b/bsnes/sfc/random/random.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/random/random.hpp b/bsnes/sfc/random/random.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/scheduler/scheduler.cpp b/bsnes/sfc/scheduler/scheduler.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/scheduler/scheduler.hpp b/bsnes/sfc/scheduler/scheduler.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/sfc.hpp b/bsnes/sfc/sfc.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/smp/memory.cpp b/bsnes/sfc/smp/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/smp/serialization.cpp b/bsnes/sfc/smp/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/smp/smp.cpp b/bsnes/sfc/smp/smp.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/smp/smp.hpp b/bsnes/sfc/smp/smp.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/smp/timing.cpp b/bsnes/sfc/smp/timing.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/system/audio.cpp b/bsnes/sfc/system/audio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/system/audio.hpp b/bsnes/sfc/system/audio.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/system/input.cpp b/bsnes/sfc/system/input.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/system/input.hpp b/bsnes/sfc/system/input.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/system/serialization.cpp b/bsnes/sfc/system/serialization.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/system/system.cpp b/bsnes/sfc/system/system.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/system/system.hpp b/bsnes/sfc/system/system.hpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/system/video.cpp b/bsnes/sfc/system/video.cpp old mode 100755 new mode 100644 diff --git a/bsnes/sfc/system/video.hpp b/bsnes/sfc/system/video.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/Makefile b/bsnes/target-ethos/Makefile old mode 100755 new mode 100644 index a7606d94..a42fcac5 --- a/bsnes/target-ethos/Makefile +++ b/bsnes/target-ethos/Makefile @@ -5,6 +5,7 @@ include fc/Makefile include sfc/Makefile include gb/Makefile include gba/Makefile +include nds/Makefile name := bsnes ui_objects := ui-ethos ui-configuration ui-interface ui-utility @@ -56,8 +57,11 @@ obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*) $(call compile,$(phoenixflags)) obj/resource.o: $(ui)/resource.rc -# windres --target=pe-i386 $(ui)/resource.rc obj/resource.o +ifeq ($(arch),win32) + windres --target=pe-i386 $(ui)/resource.rc obj/resource.o +else windres $(ui)/resource.rc obj/resource.o +endif # targets build: $(objects) diff --git a/bsnes/target-ethos/bootstrap.cpp b/bsnes/target-ethos/bootstrap.cpp old mode 100755 new mode 100644 index 00d8ff79..93b2f1d8 --- a/bsnes/target-ethos/bootstrap.cpp +++ b/bsnes/target-ethos/bootstrap.cpp @@ -2,6 +2,7 @@ #include #include #include +#include void Application::bootstrap() { interface = new Interface; @@ -10,6 +11,7 @@ void Application::bootstrap() { emulator.append(new SuperFamicom::Interface); emulator.append(new GameBoy::Interface); emulator.append(new GameBoyAdvance::Interface); + emulator.append(new NintendoDS::Interface); for(auto &system : emulator) system->bind = interface; } diff --git a/bsnes/target-ethos/configuration/configuration.cpp b/bsnes/target-ethos/configuration/configuration.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/configuration/configuration.hpp b/bsnes/target-ethos/configuration/configuration.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/ethos.cpp b/bsnes/target-ethos/ethos.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/ethos.hpp b/bsnes/target-ethos/ethos.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/general/browser.cpp b/bsnes/target-ethos/general/browser.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/general/browser.hpp b/bsnes/target-ethos/general/browser.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/general/dip-switches.cpp b/bsnes/target-ethos/general/dip-switches.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/general/dip-switches.hpp b/bsnes/target-ethos/general/dip-switches.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/general/general.cpp b/bsnes/target-ethos/general/general.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/general/general.hpp b/bsnes/target-ethos/general/general.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/general/presentation.cpp b/bsnes/target-ethos/general/presentation.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/general/presentation.hpp b/bsnes/target-ethos/general/presentation.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/input/hotkeys.cpp b/bsnes/target-ethos/input/hotkeys.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/input/input.cpp b/bsnes/target-ethos/input/input.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/input/input.hpp b/bsnes/target-ethos/input/input.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/interface/interface.cpp b/bsnes/target-ethos/interface/interface.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/interface/interface.hpp b/bsnes/target-ethos/interface/interface.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/resource.rc b/bsnes/target-ethos/resource.rc old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/resource/folder.png b/bsnes/target-ethos/resource/folder.png old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/resource/game.png b/bsnes/target-ethos/resource/game.png old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/resource/home.png b/bsnes/target-ethos/resource/home.png old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/resource/resource.cpp b/bsnes/target-ethos/resource/resource.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/resource/resource.hpp b/bsnes/target-ethos/resource/resource.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/resource/resource.xml b/bsnes/target-ethos/resource/resource.xml old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/resource/up.png b/bsnes/target-ethos/resource/up.png old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/audio.cpp b/bsnes/target-ethos/settings/audio.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/audio.hpp b/bsnes/target-ethos/settings/audio.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/driver.cpp b/bsnes/target-ethos/settings/driver.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/driver.hpp b/bsnes/target-ethos/settings/driver.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/hotkey.cpp b/bsnes/target-ethos/settings/hotkey.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/hotkey.hpp b/bsnes/target-ethos/settings/hotkey.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/input.cpp b/bsnes/target-ethos/settings/input.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/input.hpp b/bsnes/target-ethos/settings/input.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/settings.cpp b/bsnes/target-ethos/settings/settings.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/settings.hpp b/bsnes/target-ethos/settings/settings.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/timing.cpp b/bsnes/target-ethos/settings/timing.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/timing.hpp b/bsnes/target-ethos/settings/timing.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/video.cpp b/bsnes/target-ethos/settings/video.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/settings/video.hpp b/bsnes/target-ethos/settings/video.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/tools/cheat-database.cpp b/bsnes/target-ethos/tools/cheat-database.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/tools/cheat-database.hpp b/bsnes/target-ethos/tools/cheat-database.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/tools/cheat-editor.cpp b/bsnes/target-ethos/tools/cheat-editor.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/tools/cheat-editor.hpp b/bsnes/target-ethos/tools/cheat-editor.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/tools/state-manager.cpp b/bsnes/target-ethos/tools/state-manager.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/tools/state-manager.hpp b/bsnes/target-ethos/tools/state-manager.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/tools/tools.cpp b/bsnes/target-ethos/tools/tools.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/tools/tools.hpp b/bsnes/target-ethos/tools/tools.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/utility/utility.cpp b/bsnes/target-ethos/utility/utility.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/utility/utility.hpp b/bsnes/target-ethos/utility/utility.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/window/window.cpp b/bsnes/target-ethos/window/window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-ethos/window/window.hpp b/bsnes/target-ethos/window/window.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/Makefile b/bsnes/target-laevateinn/Makefile old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/base.hpp b/bsnes/target-laevateinn/base.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/breakpoint/breakpoint.cpp b/bsnes/target-laevateinn/breakpoint/breakpoint.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/breakpoint/breakpoint.hpp b/bsnes/target-laevateinn/breakpoint/breakpoint.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/console/about.cpp b/bsnes/target-laevateinn/console/about.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/console/console.cpp b/bsnes/target-laevateinn/console/console.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/console/console.hpp b/bsnes/target-laevateinn/console/console.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/cpu/cpu.cpp b/bsnes/target-laevateinn/cpu/cpu.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/cpu/cpu.hpp b/bsnes/target-laevateinn/cpu/cpu.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/cpu/registers.cpp b/bsnes/target-laevateinn/cpu/registers.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/debugger/debugger.cpp b/bsnes/target-laevateinn/debugger/debugger.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/debugger/debugger.hpp b/bsnes/target-laevateinn/debugger/debugger.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/debugger/hook.cpp b/bsnes/target-laevateinn/debugger/hook.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/debugger/usage.cpp b/bsnes/target-laevateinn/debugger/usage.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/interface/interface.cpp b/bsnes/target-laevateinn/interface/interface.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/interface/interface.hpp b/bsnes/target-laevateinn/interface/interface.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/main.cpp b/bsnes/target-laevateinn/main.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/memory/memory.cpp b/bsnes/target-laevateinn/memory/memory.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/memory/memory.hpp b/bsnes/target-laevateinn/memory/memory.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/properties/properties.cpp b/bsnes/target-laevateinn/properties/properties.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/properties/properties.hpp b/bsnes/target-laevateinn/properties/properties.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/resource.rc b/bsnes/target-laevateinn/resource.rc old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/settings/settings.cpp b/bsnes/target-laevateinn/settings/settings.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/settings/settings.hpp b/bsnes/target-laevateinn/settings/settings.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/smp/registers.cpp b/bsnes/target-laevateinn/smp/registers.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/smp/smp.cpp b/bsnes/target-laevateinn/smp/smp.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/smp/smp.hpp b/bsnes/target-laevateinn/smp/smp.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/tracer/tracer.cpp b/bsnes/target-laevateinn/tracer/tracer.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/tracer/tracer.hpp b/bsnes/target-laevateinn/tracer/tracer.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/video/video.cpp b/bsnes/target-laevateinn/video/video.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/video/video.hpp b/bsnes/target-laevateinn/video/video.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/vram/vram.cpp b/bsnes/target-laevateinn/vram/vram.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/vram/vram.hpp b/bsnes/target-laevateinn/vram/vram.hpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/window/window.cpp b/bsnes/target-laevateinn/window/window.cpp old mode 100755 new mode 100644 diff --git a/bsnes/target-laevateinn/window/window.hpp b/bsnes/target-laevateinn/window/window.hpp old mode 100755 new mode 100644 diff --git a/kaijuu/Makefile b/kaijuu/Makefile new file mode 100644 index 00000000..63b1d771 --- /dev/null +++ b/kaijuu/Makefile @@ -0,0 +1,18 @@ +# for Linux only; to synchronize includes and resources +# use cc32.bat and cc64.bat for Windows compilation + +include nall/Makefile + +resource: force + sourcery resource/resource.xml resource/resource.cpp resource/resource.hpp + +sync: + if [ -d ./nall ]; then rm -r ./nall; fi + if [ -d ./phoenix ]; then rm -r ./phoenix; fi + cp -r ../nall ./nall + cp -r ../phoenix ./phoenix + rm -r nall/test + rm -r phoenix/nall + rm -r phoenix/test + +force: diff --git a/kaijuu/cc32.bat b/kaijuu/cc32.bat new file mode 100755 index 00000000..60caa857 --- /dev/null +++ b/kaijuu/cc32.bat @@ -0,0 +1,8 @@ +windres --target=pe-i386 kaijuu.rc kaijuu-resource.o +g++ -m32 -I. -std=gnu++0x -O3 -fomit-frame-pointer -c kaijuu.cpp +g++ -m32 -shared -static-libgcc -Wl,kaijuu.def -Wl,-enable-stdcall-fixup -s -o kaijuu32.dll kaijuu.o -lm -lole32 -luuid -lshlwapi +g++ -m32 -I. -std=gnu++0x -O3 -fomit-frame-pointer -o phoenix.o -c phoenix/phoenix.cpp -DPHOENIX_WINDOWS +g++ -m32 -I. -std=gnu++0x -O3 -fomit-frame-pointer -c interface.cpp +g++ -m32 -mwindows -s -o kaijuu32.exe interface.o kaijuu-resource.o phoenix.o -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -lshlwapi +@pause +@del *.o diff --git a/kaijuu/cc64.bat b/kaijuu/cc64.bat new file mode 100755 index 00000000..01b65370 --- /dev/null +++ b/kaijuu/cc64.bat @@ -0,0 +1,8 @@ +windres kaijuu.rc kaijuu-resource.o +g++ -m64 -I. -std=gnu++0x -O3 -fomit-frame-pointer -c kaijuu.cpp +g++ -m64 -shared -static-libgcc -Wl,kaijuu.def -Wl,-enable-stdcall-fixup -s -o kaijuu64.dll kaijuu.o -lm -lole32 -luuid -lshlwapi +g++ -m64 -I. -std=gnu++0x -O3 -fomit-frame-pointer -o phoenix.o -c phoenix/phoenix.cpp -DPHOENIX_WINDOWS +g++ -m64 -I. -std=gnu++0x -O3 -fomit-frame-pointer -c interface.cpp +g++ -m64 -mwindows -s -o kaijuu64.exe interface.o kaijuu-resource.o phoenix.o -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -lshlwapi +@pause +@del *.o diff --git a/kaijuu/extension.cpp b/kaijuu/extension.cpp new file mode 100644 index 00000000..512a4184 --- /dev/null +++ b/kaijuu/extension.cpp @@ -0,0 +1,175 @@ +CShellExt::CShellExt() { + instanceCount = 0; + referenceCount++; +} + +CShellExt::~CShellExt() { + referenceCount--; +} + +STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID *ppv) { + *ppv = nullptr; + + if(IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown)) { + *ppv = (IShellExtInit*)this; + } else if(IsEqualIID(riid, IID_IContextMenu)) { + *ppv = (IContextMenu*)this; + } + + if(*ppv) { + AddRef(); + return NOERROR; + } + + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) CShellExt::AddRef() { + return ++instanceCount; +} + +STDMETHODIMP_(ULONG) CShellExt::Release() { + if(--instanceCount) return instanceCount; + delete this; + return 0; +} + +STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder, IDataObject *pDataObject, HKEY hRegKey) { + fileList.reset(); + + if(pDataObject) { + wchar_t filename[PATH_MAX]; + STGMEDIUM medium; + FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + HDROP hDrop; + + if(FAILED(pDataObject->GetData(&fe, &medium))) return E_INVALIDARG; + hDrop = (HDROP)GlobalLock(medium.hGlobal); + if(hDrop == NULL) return E_INVALIDARG; + + fileList.reset(); + unsigned count = DragQueryFileW(hDrop, 0xffffffff, NULL, 0); + for(unsigned i = 0; i < count; i++) { + DragQueryFileW((HDROP)medium.hGlobal, i, filename, PATH_MAX); + string name = (const char*)utf8_t(filename); + name.transform("/", "\\"); + if(name.endswith("\\")) name.rtrim<1>("\\"); + fileList.append(name); + } + GlobalUnlock(medium.hGlobal); + ReleaseStgMedium(&medium); + } + + return S_OK; +} + +STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { + settings.load(); + unsigned idCmd = idCmdFirst; + bool firstDefault = true; + + auto ruleIDs = matchedRules(); + for(auto &ruleID : ruleIDs) { + auto &rule = settings.rules(ruleID); + if(idCmd < idCmdLast) { + InsertMenuW(hMenu, indexMenu, MF_STRING | MF_BYPOSITION, idCmd++, (const wchar_t*)utf16_t(rule.name)); + if(rule.defaultAction && firstDefault) { + firstDefault = false; //there can be only one default menu item + SetMenuDefaultItem(hMenu, indexMenu, TRUE); + } + indexMenu++; + } + } + + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(idCmd - idCmdFirst)); +} + +STDMETHODIMP CShellExt::GetCommandString(UINT_PTR idCmd, UINT uFlags, LPUINT lpReserved, LPSTR pszName, UINT uMaxNameLen) { + if(idCmd < settings.rules.size()) return S_OK; + return E_INVALIDARG; +} + +STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) { + if(HIWORD(lpcmi->lpVerb) != 0) return E_INVALIDARG; //ignore actual string verbs + + settings.load(); + unsigned id = LOWORD(lpcmi->lpVerb); + auto ruleIDs = matchedRules(); + auto &rule = settings.rules(ruleIDs(id)); + + string nameID = fileList(0); + string pathnameID = dir(nameID).rtrim<1>("\\"); + string filenameID = notdir(nameID); + string basenameID = notdir(nall::basename(nameID)); + string extensionID = extension(nameID); + + string pathID = {"\"", pathnameID, "\""}; + string fileID = {"\"", nameID, "\""}; + + string pathsID, filesID; + for(auto &filename : fileList) pathsID.append("\"", dir(filename).rtrim<1>("\\"), "\"", " "); + for(auto &filename : fileList) filesID.append("\"", filename, "\"", " "); + pathsID.rtrim<1>(" "), filesID.rtrim<1>(" "); + + lstring params = rule.command.qsplit<1>(" "); + params(1).replace("{name}", nameID); + params(1).replace("{pathname}", pathnameID); + params(1).replace("{filename}", filenameID); + params(1).replace("{basename}", basenameID); + params(1).replace("{extension}", extensionID); + + params(1).replace("{path}", pathID); + params(1).replace("{file}", fileID); + + params(1).replace("{paths}", pathsID); + params(1).replace("{files}", filesID); + + if((intptr_t)ShellExecuteW(NULL, L"open", utf16_t(params(0)), utf16_t(params(1)), utf16_t(pathnameID), SW_SHOWNORMAL) <= 32) { + MessageBoxW(0, L"Error opening associated program.", L"kaijuu", MB_OK); + } + + return S_OK; +} + +vector CShellExt::matchedRules() { + vector matched; + if(fileList.size() == 0) return matched; + + for(unsigned id = 0; id < settings.rules.size(); id++) { + auto &rule = settings.rules(id); + if(rule.multiSelection == false && fileList.size() > 1) continue; + bool proceed = true; + for(auto &filename : fileList) { + string name = filename; + if(directory::exists(name)) { + if(rule.matchFolders == false) { + proceed = false; + break; + } + } else { + if(rule.matchFiles == false) { + proceed = false; + break; + } + } + name = notdir(name); + + lstring patternList = rule.pattern.split(";"); + bool found = false; + for(auto &pattern : patternList) { + if(name.wildcard(pattern)) { + found = true; + break; + } + } + if(found == false) { + proceed = false; + break; + } + } + if(proceed == false) continue; + matched.append(id); + } + + return matched; +} diff --git a/kaijuu/extension.hpp b/kaijuu/extension.hpp new file mode 100644 index 00000000..424ba4d5 --- /dev/null +++ b/kaijuu/extension.hpp @@ -0,0 +1,23 @@ +struct CShellExt : IContextMenu, IShellExtInit { +protected: + unsigned instanceCount; + lstring fileList; + +public: + CShellExt(); + ~CShellExt(); + + STDMETHODIMP QueryInterface(REFIID, LPVOID*); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + STDMETHODIMP QueryContextMenu(HMENU, UINT, UINT, UINT, UINT); + STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO); + STDMETHODIMP GetCommandString(UINT_PTR, UINT, UINT FAR*, LPSTR, UINT); + STDMETHODIMP Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY); + +private: + vector matchedRules(); +}; + +typedef CShellExt *LPCSHELLEXT; \ No newline at end of file diff --git a/kaijuu/factory.cpp b/kaijuu/factory.cpp new file mode 100644 index 00000000..86503ab1 --- /dev/null +++ b/kaijuu/factory.cpp @@ -0,0 +1,40 @@ +CShellExtClassFactory::CShellExtClassFactory() { + instanceCount = 0; + referenceCount++; +} + +CShellExtClassFactory::~CShellExtClassFactory() { + referenceCount--; +} + +STDMETHODIMP CShellExtClassFactory::QueryInterface(REFIID riid, LPVOID *ppv) { + *ppv = NULL; + if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) { + *ppv = (LPCLASSFACTORY)this; + AddRef(); + return NOERROR; + } + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef() { + return ++instanceCount; +} + +STDMETHODIMP_(ULONG) CShellExtClassFactory::Release() { + if(--instanceCount) return instanceCount; + delete this; + return 0; +} + +STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnknownOuter, REFIID riid, LPVOID *ppv) { + *ppv = NULL; + if(pUnknownOuter) return CLASS_E_NOAGGREGATION; + CShellExt *pShellExt = new CShellExt(); + if(pShellExt == NULL) return E_OUTOFMEMORY; + return pShellExt->QueryInterface(riid, ppv); +} + +STDMETHODIMP CShellExtClassFactory::LockServer(BOOL fLock) { + return NOERROR; +} diff --git a/kaijuu/factory.hpp b/kaijuu/factory.hpp new file mode 100644 index 00000000..48d305b1 --- /dev/null +++ b/kaijuu/factory.hpp @@ -0,0 +1,17 @@ +struct CShellExtClassFactory : IClassFactory { +protected: + unsigned instanceCount; + +public: + CShellExtClassFactory(); + ~CShellExtClassFactory(); + + STDMETHODIMP QueryInterface(REFIID, LPVOID FAR*); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR*); + STDMETHODIMP LockServer(BOOL); +}; + +typedef CShellExtClassFactory *LPCSHELLEXTCLASSFACTORY; diff --git a/kaijuu/guid.hpp b/kaijuu/guid.hpp new file mode 100644 index 00000000..815d6702 --- /dev/null +++ b/kaijuu/guid.hpp @@ -0,0 +1,11 @@ +#ifdef _WIN64 + DEFINE_GUID(CLSID_ShellExtension, 0x5c8ee773, 0xb9dc, 0xcec7, 0x63, 0x31, 0x98, 0x6c, 0x16, 0x2b, 0x15, 0x0a); + const char classID[] = "{5c8ee773-b9dc-cec7-6331-986c162b150a}"; + const char classDescription[] = "KaijuuOpenShEx64"; + const char classDriver[] = "kaijuu64.dll"; +#else + DEFINE_GUID(CLSID_ShellExtension, 0xa2f1781c, 0x2e37, 0x9bcd, 0x66, 0x93, 0xc9, 0xe4, 0x52, 0x89, 0xc4, 0xc2); + const char classID[] = "{a2f1781c-2e37-9bcd-6693-c9e45289c4c2}"; + const char classDescription[] = "KaijuuOpenShEx32"; + const char classDriver[] = "kaijuu32.dll"; +#endif diff --git a/kaijuu/interface.cpp b/kaijuu/interface.cpp new file mode 100644 index 00000000..68b4b19f --- /dev/null +++ b/kaijuu/interface.cpp @@ -0,0 +1,307 @@ +#include "interface.hpp" +Application *application = nullptr; +RuleEditor *ruleEditor = nullptr; + +#include "resource/resource.hpp" +#include "resource/resource.cpp" + +Application::Application(const string &pathname) : pathname(pathname) { + setTitle("kaijuu v05"); + setFrameGeometry({64, 64, 725, 480}); + + layout.setMargin(5); + statusLabel.setFont("Tahoma, 8, Bold"); + uninstallButton.setText("Uninstall"); + installButton.setText("Install"); + settingList.setHeaderText("Name", "Default", "Match", "Pattern", "Command"); + settingList.setHeaderVisible(); + appendButton.setText("Append"); + modifyButton.setText("Modify"); + moveUpButton.setText("Move Up"); + moveDownButton.setText("Move Down"); + removeButton.setText("Remove"); + resetButton.setText("Reset"); + helpButton.setText("Help ..."); + + append(layout); + layout.append(installLayout, {~0, 0}, 5); + installLayout.append(statusLabel, {~0, 0}, 5); + installLayout.append(uninstallButton, {80, 0}, 5); + installLayout.append(installButton, {80, 0}); + layout.append(settingLayout, {~0, ~0}); + settingLayout.append(settingList, {~0, ~0}, 5); + settingLayout.append(controlLayout, {0, ~0}); + controlLayout.append(appendButton, {80, 0}, 5); + controlLayout.append(modifyButton, {80, 0}, 5); + controlLayout.append(moveUpButton, {80, 0}, 5); + controlLayout.append(moveDownButton, {80, 0}, 5); + controlLayout.append(removeButton, {80, 0}, 5); + controlLayout.append(spacer, {0, ~0}); + controlLayout.append(resetButton, {80, 0}, 5); + controlLayout.append(helpButton, {80, 0}, 5); + controlLayout.append(canvas, {80, 88}); + + canvas.setImage({resource::icon, sizeof resource::icon}); + canvas.update(); + + onClose = &OS::quit; + installButton.onActivate = {&Application::install, this}; + uninstallButton.onActivate = {&Application::uninstall, this}; + settingList.onActivate = {&Application::modifyAction, this}; + settingList.onChange = {&Application::synchronize, this}; + appendButton.onActivate = {&Application::appendAction, this}; + modifyButton.onActivate = {&Application::modifyAction, this}; + moveUpButton.onActivate = {&Application::moveUpAction, this}; + moveDownButton.onActivate = {&Application::moveDownAction, this}; + removeButton.onActivate = {&Application::removeAction, this}; + resetButton.onActivate = {&Application::resetAction, this}; + helpButton.onActivate = [&] { nall::invoke("kaijuu.html"); }; + refresh(); + synchronize(); + setVisible(); +} + +void Application::synchronize() { + if(registry::read({"HKLM/Software/Microsoft/Windows/CurrentVersion/Shell Extensions/Approved/", classID}) == classDescription) { + statusLabel.setText("Extension status: installed"); + installButton.setEnabled(false); + uninstallButton.setEnabled(true); + } else { + statusLabel.setText("Extension status: not installed"); + installButton.setEnabled(true); + uninstallButton.setEnabled(false); + } + modifyButton.setEnabled(settingList.selected()); + moveUpButton.setEnabled(settingList.selected() && settings.rules.size() > 1 && settingList.selection() != 0); + moveDownButton.setEnabled(settingList.selected() && settings.rules.size() > 1 && settingList.selection() < settings.rules.size() - 1); + removeButton.setEnabled(settingList.selected()); + resetButton.setEnabled(settings.rules.size() > 0); +} + +void Application::refresh() { + settings.load(); + settingList.reset(); + for(auto &rule : settings.rules) { + string match = "Nothing"; + if(rule.matchFiles && rule.matchFolders) match = "Everything"; + else if(rule.matchFiles) match = "Files"; + else if(rule.matchFolders) match = "Folders"; + settingList.append(rule.name, rule.defaultAction ? "Yes" : "No", match, rule.pattern, rule.command); + } + settingList.autoSizeColumns(); +} + +void Application::install() { + string command = {"regsvr32 \"", pathname, classDriver, "\""}; + _wsystem(utf16_t(command)); + synchronize(); +} + +void Application::uninstall() { + string command = {"regsvr32 /u \"", pathname, classDriver, "\""}; + _wsystem(utf16_t(command)); + synchronize(); +} + +void Application::appendAction() { + ruleEditor->show(); +} + +void Application::modifyAction() { + if(settingList.selected() == false) return; + unsigned selection = settingList.selection(); + ruleEditor->show(selection); +} + +void Application::moveUpAction() { + if(settingList.selected() == false) return; + if(settingList.selection() == 0) return; + unsigned selection = settingList.selection(); + auto temp = settings.rules(selection - 1); + settings.rules(selection - 1) = settings.rules(selection); + settings.rules(selection) = temp; + settings.save(); + refresh(); + settingList.setSelection(selection - 1); + synchronize(); +} + +void Application::moveDownAction() { + if(settingList.selected() == false) return; + if(settingList.selection() >= settings.rules.size() - 1) return; + unsigned selection = settingList.selection(); + auto temp = settings.rules(selection + 1); + settings.rules(selection + 1) = settings.rules(selection); + settings.rules(selection) = temp; + settings.save(); + refresh(); + settingList.setSelection(selection + 1); + synchronize(); +} + +void Application::removeAction() { + if(settingList.selected() == false) return; + unsigned selection = settingList.selection(); + settings.rules.remove(selection); + settings.save(); + refresh(); + synchronize(); +} + +void Application::resetAction() { + if(MessageWindow::question(*this, "Warning: this will permanently remove all rules! Are you sure you want to do this?") + == MessageWindow::Response::No) return; + settings.rules.reset(); + settings.save(); + refresh(); + synchronize(); +} + +RuleEditor::RuleEditor() : index(-1) { + setTitle("Rule Editor"); + setFrameGeometry({128, 256, 500, 160}); + + layout.setMargin(5); + nameLabel.setText("Name:"); + patternLabel.setText("Pattern:"); + commandLabel.setText("Command:"); + commandSelect.setText("Select ..."); + defaultAction.setText("Default Action"); + filesAction.setText("Match Files"); + foldersAction.setText("Match Folders"); + assignButton.setText("Assign"); + + Font font("Tahoma, 8"); + unsigned length = 0; + length = max(length, font.geometry("Name:").width); + length = max(length, font.geometry("Pattern:").width); + length = max(length, font.geometry("Command:").width); + + append(layout); + layout.append(nameLayout, {~0, 0}, 5); + nameLayout.append(nameLabel, {length, 0}, 5); + nameLayout.append(nameValue, {~0, 0}); + layout.append(patternLayout, {~0, 0}, 5); + patternLayout.append(patternLabel, {length, 0}, 5); + patternLayout.append(patternValue, {~0, 0}); + layout.append(commandLayout, {~0, 0}, 5); + commandLayout.append(commandLabel, {length, 0}, 5); + commandLayout.append(commandValue, {~0, 0}, 5); + commandLayout.append(commandSelect, {80, 0}); + layout.append(controlLayout, {~0, 0}); + controlLayout.append(defaultAction, {0, 0}, 5); + controlLayout.append(filesAction, {0, 0}, 5); + controlLayout.append(foldersAction, {0, 0}, 5); + controlLayout.append(spacer, {~0, 0}); + controlLayout.append(assignButton, {80, 0}); + + Geometry geometry = Window::geometry(); + geometry.height = layout.minimumGeometry().height; + setGeometry(geometry); + + onClose = [&] { + modal = false; + }; + + nameValue.onChange = + patternValue.onChange = + commandValue.onChange = + {&RuleEditor::synchronize, this}; + + commandSelect.onActivate = [&] { + string pathname = DialogWindow::fileOpen(*this, application->pathname, "Programs (*.exe)", "All Files (*)"); + if(pathname.empty() == false) { + pathname.transform("/", "\\"); + commandValue.setText({"\"", pathname, "\" {file}"}); + } + synchronize(); + }; + + nameValue.onActivate = + patternValue.onActivate = + commandValue.onActivate = + assignButton.onActivate = [&] { + Settings::Rule rule = { + nameValue.text(), + patternValue.text(), + defaultAction.checked(), + filesAction.checked(), + foldersAction.checked(), + commandValue.text() + }; + if(index == -1) { + settings.rules.append(rule); + } else { + settings.rules(index) = rule; + } + settings.save(); + application->refresh(); + application->synchronize(); + setVisible(false); + modal = false; + }; +} + +void RuleEditor::synchronize() { + bool enable = true; + if(nameValue.text().empty()) enable = false; + if(patternValue.text().empty()) enable = false; + if(commandValue.text().empty()) enable = false; + assignButton.setEnabled(enable); +} + +void RuleEditor::show(signed ruleID) { + Settings::Rule rule{"", "", false, true, false, "", false}; + if(ruleID >= 0) rule = settings.rules(ruleID); + + index = ruleID; + nameValue.setText(rule.name); + patternValue.setText(rule.pattern); + commandValue.setText(rule.command); + defaultAction.setChecked(rule.defaultAction); + filesAction.setChecked(rule.matchFiles); + foldersAction.setChecked(rule.matchFolders); + synchronize(); + setVisible(); + setFocused(); + nameValue.setFocused(); + + setModal(modal = true); + while(modal == true) { + OS::processEvents(); + } + setModal(false); + application->setFocused(); +} + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL); + +bool isWow64() { + LPFN_ISWOW64PROCESS fnIsWow64Process; + fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process"); + if(!fnIsWow64Process) return false; + BOOL result = FALSE; + fnIsWow64Process(GetCurrentProcess(), &result); + return result == TRUE; +} + +int CALLBACK WinMain(HINSTANCE module, HINSTANCE, LPSTR, int) { + if(isWow64()) { + MessageWindow::critical(Window::none(), "Error: you must run kaijuu64.exe on 64-bit Windows."); + return 0; + } + + wchar_t filename[MAX_PATH]; + GetModuleFileNameW(module, filename, MAX_PATH); + + string pathname = (const char*)utf8_t(filename); + pathname.transform("\\", "/"); + pathname = dir(pathname); + + application = new Application(pathname); + ruleEditor = new RuleEditor; + application->setFocused(); + OS::main(); + + return 0; +} diff --git a/kaijuu/interface.hpp b/kaijuu/interface.hpp new file mode 100644 index 00000000..656cb7e3 --- /dev/null +++ b/kaijuu/interface.hpp @@ -0,0 +1,72 @@ +#include +#include +#include +#include +using namespace nall; + +#include +using namespace phoenix; + +#include "guid.hpp" +#include "settings.hpp" + +struct Application : Window { + VerticalLayout layout; + HorizontalLayout installLayout; + Label statusLabel; + Button uninstallButton; + Button installButton; + HorizontalLayout settingLayout; + ListView settingList; + VerticalLayout controlLayout; + Button appendButton; + Button modifyButton; + Button moveUpButton; + Button moveDownButton; + Button removeButton; + Button resetButton; + Widget spacer; + Button helpButton; + Canvas canvas; + + Application(const string &pathname); + void synchronize(); + void refresh(); + void install(); + void uninstall(); + void appendAction(); + void modifyAction(); + void moveUpAction(); + void moveDownAction(); + void removeAction(); + void resetAction(); + + string pathname; +}; + +struct RuleEditor : Window { + VerticalLayout layout; + HorizontalLayout nameLayout; + Label nameLabel; + LineEdit nameValue; + HorizontalLayout patternLayout; + Label patternLabel; + LineEdit patternValue; + HorizontalLayout commandLayout; + Label commandLabel; + LineEdit commandValue; + Button commandSelect; + HorizontalLayout controlLayout; + CheckBox defaultAction; + CheckBox filesAction; + CheckBox foldersAction; + Widget spacer; + Button assignButton; + + bool modal; + signed index; + + RuleEditor(); + void synchronize(); + void show(signed rule = -1); +}; diff --git a/kaijuu/kaijuu.Manifest b/kaijuu/kaijuu.Manifest new file mode 100644 index 00000000..28987b10 --- /dev/null +++ b/kaijuu/kaijuu.Manifest @@ -0,0 +1,21 @@ + + + + + + + + + + + true + + + + + + + + + + diff --git a/kaijuu/kaijuu.cpp b/kaijuu/kaijuu.cpp new file mode 100644 index 00000000..d9eaa535 --- /dev/null +++ b/kaijuu/kaijuu.cpp @@ -0,0 +1,50 @@ +#include "kaijuu.hpp" +#include "extension.cpp" +#include "factory.cpp" + +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD dwReason, LPVOID lpReserved) { + if(dwReason == DLL_PROCESS_ATTACH) { + module = hinstance; + } + + if(dwReason == DLL_PROCESS_DETACH) { + } + + return TRUE; +} + +STDAPI DllCanUnloadNow() { + return referenceCount == 0 ? S_OK : S_FALSE; +} + +STDAPI DllRegisterServer() { + wchar_t fileName[MAX_PATH]; + GetModuleFileNameW(module, fileName, MAX_PATH); + registry::write({"HKCR/CLSID/", classID, "/"}, classDescription); + registry::write({"HKCR/CLSID/", classID, "/shellex/MayChangeDefaultMenu/"}); + registry::write({"HKCR/CLSID/", classID, "/InprocServer32/"}, (const char*)utf8_t(fileName)); + registry::write({"HKCR/CLSID/", classID, "/InprocServer32/ThreadingModel"}, "Apartment"); + registry::write({"HKCR/*/shellex/ContextMenuHandlers/", classDescription, "/"}, classID); + registry::write({"HKCR/Directory/shellex/ContextMenuHandlers/", classDescription, "/"}, classID); + registry::write({"HKLM/Software/Microsoft/Windows/CurrentVersion/Shell Extensions/Approved/", classID}, classDescription); + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); + return S_OK; +} + +STDAPI DllUnregisterServer() { + registry::remove({"HKCR/CLSID/", classID, "/"}); + registry::remove({"HKCR/*/shellex/ContextMenuHandlers/", classDescription, "/"}); + registry::remove({"HKCR/Directory/shellex/ContextMenuHandlers/", classDescription, "/"}); + registry::remove({"HKLM/Software/Microsoft/Windows/CurrentVersion/Shell Extensions/Approved/", classID}); + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); + return S_OK; +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { + *ppv = NULL; + if(IsEqualIID(rclsid, CLSID_ShellExtension)) { + CShellExtClassFactory *pcf = new CShellExtClassFactory; + return pcf->QueryInterface(riid, ppv); + } + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/kaijuu/kaijuu.def b/kaijuu/kaijuu.def new file mode 100644 index 00000000..ce78749c --- /dev/null +++ b/kaijuu/kaijuu.def @@ -0,0 +1,5 @@ +EXPORTS + DllRegisterServer private + DllUnregisterServer private + DllCanUnloadNow private + DllGetClassObject private diff --git a/kaijuu/kaijuu.hpp b/kaijuu/kaijuu.hpp new file mode 100644 index 00000000..93e4f3ab --- /dev/null +++ b/kaijuu/kaijuu.hpp @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include +#include +using namespace nall; + +#define INITGUID +#include +#include +#include +#include +#include +#include +#include +#define IDM_CFOPEN 0 + +HINSTANCE module = NULL; +unsigned referenceCount = 0; + +#include "guid.hpp" +#include "settings.hpp" +#include "extension.hpp" +#include "factory.hpp" diff --git a/kaijuu/kaijuu.html b/kaijuu/kaijuu.html new file mode 100644 index 00000000..65bcdb59 --- /dev/null +++ b/kaijuu/kaijuu.html @@ -0,0 +1,200 @@ + + + kaijuu User Manual + + + +

kaijuu v05

+ Author: byuu
+ License: ISC
+
+ +

Overview

+

kaijuu is a Windows context menu shell extension. The context + menu is the list you see when you right-click on a file or folder. + kaijuu allows you to add your own custom actions to this menu.

+ +

Think of opening an unknown file type: Windows will ask you to + associate a program with the file type. From there forward, + double-clicking the file will open the file with that program.

+ +

kaijuu is a far more powerful version of this same concept. With + kaijuu, you can assign as many rules as you want. You can apply the + same rule to multiple file patterns. You can have more complex + pattern matching for names. You can apply rules to folders. You can + specify rules about how to handle single-file versus multi-file + selection. You can send custom command-line parameters to the + program. You can have rules on a per-user basis. And you can do all + of this from an easy-to-use GUI.

+ +

Installation

+

kaijuu comes in 32-bit and 64-bit flavors, you will need to use + the one for your operating system. If you are unsure, try running + kaijuu32.exe. It will tell you if you need to use the 64-bit + version.

+ +

Now place the appropriate kaijuu EXE and DLL files into a folder + where you intend to keep them. The DLL cannot be moved after + installation, otherwise Explorer will not be able to locate the + shell extension. C:\Program Files\kaijuu would be a recommended + location.

+ +

Now run the kaijuu EXE, and click on Install. You must + have administrator access to use the kaijuu EXE, as this is + necessary to install and uninstall shell extensions.

+ +

Removal and Upgrading

+

To remove or upgrade kaijuu, you must first uninstall the shell + extension. Run the kaijuu EXE, and click on Uninstall. You + must now close all open instances of Windows Explorer, in order for + the DLL to be completely unloaded. In the worst case, restart the + computer.

+ +

If you intend to upgrade kaijuu, I recommend using the + Reset button to erase all saved settings. There is no + guarantee of backward-compatibility between kaijuu revisions.

+ +

Configuration

+

The kaijuu EXE not only handles installation and removal, it also + handles modifying the rules.

+ +

kaijuu stores a unique list of rules for every user account. + You are free to modify rules even while kaijuu is installed. They + will take immediate effect.

+ +

The main interface lists all rules, sorted in order of their + priority. For instance, if two rules match and both are marked as + the default action; the item higher in the list will be marked as + the default. You can also quickly determine if the extension is + currently installed.

+ +

Append will add new rules, Modify will edit an + existing rule, Move Up and Move Down can be used to + modify the priority ordering, Remove can delete the selected + rule, and Reset can delete all rules.

+ +

Rules

+

You can have as many rules as you like. You will see every + matched rule in the context menu when you right-click on files or + folders.

+ +

Name is the string that will show up in the context menu. + It would be wise to name the rule something like "Open with X" or + "Edit with Y"

+ +

Pattern is a semicolon-separated list of patterns to test + the selected file or folder names against. You must specify one or + more patterns.

+ +

Example 1: *.txt;*.doc will match anything ending + in .txt or in .doc.

+ +

Example 2: * will match everything always.

+ +

Example 3: Manifest will only match items named + Manifest.

+ +

Example 4: *.?? will match any two-letter + extension, such as .gb

+ + Command is the program to be executed when a rule is + activated. You can use the Select button to quickly navigate + to a program to use.

+ +

Note the way the program name is typically quoted, for instance + "c:\my program.exe". If there is a space in the path, this is + required to differentiate the program name from its arguments. If + you were to type your own rule, you could take advantage of two + things: first, the PATH command-line variable allows + specifying system programs without the full path. For instance, + "cmd" will invoke the command-prompt; and second, if the + program path contains no spaces, the quotes are no longer necessary. + So you could say cmd to invoke the command-prompt.

+ +

After the program name, you can specify the program arguments. + kaijuu has many special identifiers built-in, that are replaced with + the file and/or folder names that were selected. When using the + Select button, {file} is automatically appended for + convenience, which should be sufficient for most cases. You can of + course customize the rule afterward with the following identifiers: +

+ +
+{name}      = c:\path\file.txt
+{pathname}  = c:\path
+{filename}  = file.txt
+{basename}  = file
+{extension} = txt
+
+{path}  = "c:\path"
+{file}  = "c:\path\file.txt"
+
+{paths} = "c:\path1" "c:\path2"
+{files} = "c:\path1\file1.txt" "c:\path2\file2.txt"
+
+ +

Note that if you use the first group, you must add your own + quotes around the identifiers, eg notepad "{name}".

+ +

If the command includes {files} or {paths} within + the string, then kaijuu will match this rule when one or more files + are selected. If neither of these patterns are found, then kaijuu + will only check the rule if a single file is selected.

+ +

You will want to use {file} and {path} for programs + that can only open a single item a a time; and {files} and + {paths} for programs that can open multiple items at the same + time, such as music players.

+ +

Default Action, when checked, will mark this rule as the + default action to take when a file or folder is double-clicked on. +

+ +

Match Files will allow selections with files in them to + be valid. If a file is selected without this checked, the rule will + fail.

+ +

Match Folders will allow selections with folders in them + to be valid. If a file is selected without this checked, the rule + will fail.

+ +

Assign will create the new rule or modify an existing + rule, depending upon which button you clicked from the main window. +

+ +

Caution: be very careful when using a pattern of * + along with Default Action checked. For instance, you could + find that double-clicking executables no longer opens then, and + requires you to use the right-click context menu. In the worst case, + you will have to reboot into safe mode and delete the rule or kaijuu + DLL.

+ +

Rule Examples

+ + + + + + +
NameDefaultMatchPatternCommand
Open terminal hereNoFolders*cmd /k cd /d {path}
Edit MakefileYesFilesMakefilenotepad {file}
Play song(s)NoFiles*.mp3"c:\winamp.exe" {files}
Load as Game FolderYesFolders*.fc;*.sfc;*.gba"c:\bsnes.exe" {path}
+ + diff --git a/kaijuu/kaijuu.rc b/kaijuu/kaijuu.rc new file mode 100644 index 00000000..6de3fb51 --- /dev/null +++ b/kaijuu/kaijuu.rc @@ -0,0 +1 @@ +1 24 "kaijuu.manifest" diff --git a/snesfilter/nall/Makefile b/kaijuu/nall/Makefile old mode 100755 new mode 100644 similarity index 90% rename from snesfilter/nall/Makefile rename to kaijuu/nall/Makefile index a542beeb..bbc4b029 --- a/snesfilter/nall/Makefile +++ b/kaijuu/nall/Makefile @@ -19,6 +19,9 @@ ifeq ($(platform),) ifeq ($(uname),) platform := win delete = del $(subst /,\,$1) + else ifneq ($(findstring Windows,$(uname)),) + platform := win + delete = del $(subst /,\,$1) else ifneq ($(findstring CYGWIN,$(uname)),) platform := win delete = del $(subst /,\,$1) @@ -35,12 +38,15 @@ ifeq ($(compiler),) ifeq ($(platform),win) compiler := gcc else ifeq ($(platform),osx) - compiler := gcc-mp-4.6 + compiler := gcc-mp-4.7 else - compiler := gcc-4.6 + compiler := gcc-4.7 endif endif +c := $(compiler) -std=gnu99 +cpp := $(subst cc,++,$(compiler)) -std=gnu++0x + ifeq ($(prefix),) prefix := /usr/local endif diff --git a/snesfilter/nall/algorithm.hpp b/kaijuu/nall/algorithm.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/algorithm.hpp rename to kaijuu/nall/algorithm.hpp diff --git a/snesfilter/nall/any.hpp b/kaijuu/nall/any.hpp old mode 100755 new mode 100644 similarity index 84% rename from snesfilter/nall/any.hpp rename to kaijuu/nall/any.hpp index b31cff3c..7661a2a4 --- a/snesfilter/nall/any.hpp +++ b/kaijuu/nall/any.hpp @@ -2,17 +2,15 @@ #define NALL_ANY_HPP #include -#include -#include +#include namespace nall { - class any { - public: + struct any { bool empty() const { return container; } const std::type_info& type() const { return container ? container->type() : typeid(void); } template any& operator=(const T& value_) { - typedef typename static_if< + typedef typename type_if< std::is_array::value, typename std::remove_extent::type>::type*, T @@ -28,8 +26,9 @@ namespace nall { return *this; } - any() : container(0) {} - template any(const T& value_) : container(0) { operator=(value_); } + any() : container(nullptr) {} + ~any() { if(container) delete container; } + template any(const T& value_) : container(nullptr) { operator=(value_); } private: struct placeholder { @@ -61,12 +60,12 @@ namespace nall { } template T* any_cast(any *value) { - if(!value || value->type() != typeid(T)) return 0; + if(!value || value->type() != typeid(T)) return nullptr; return &static_cast*>(value->container)->value; } template const T* any_cast(const any *value) { - if(!value || value->type() != typeid(T)) return 0; + if(!value || value->type() != typeid(T)) return nullptr; return &static_cast*>(value->container)->value; } } diff --git a/snesfilter/nall/atoi.hpp b/kaijuu/nall/atoi.hpp old mode 100755 new mode 100644 similarity index 82% rename from snesfilter/nall/atoi.hpp rename to kaijuu/nall/atoi.hpp index cec3e72d..26756c79 --- a/snesfilter/nall/atoi.hpp +++ b/kaijuu/nall/atoi.hpp @@ -1,6 +1,8 @@ #ifndef NALL_ATOI_HPP #define NALL_ATOI_HPP +#include + namespace nall { //note: this header is intended to form the base for user-defined literals; @@ -79,6 +81,19 @@ constexpr inline uintmax_t hex(const char *s) { ); } +constexpr inline intmax_t numeral(const char *s) { + return ( + *s == '0' && *(s + 1) == 'X' ? hex_(s + 2) : + *s == '0' && *(s + 1) == 'x' ? hex_(s + 2) : + *s == '0' && *(s + 1) == 'B' ? binary_(s + 2) : + *s == '0' && *(s + 1) == 'b' ? binary_(s + 2) : + *s == '0' ? octal_(s + 1) : + *s == '+' ? +decimal_(s + 1) : + *s == '-' ? -decimal_(s + 1) : + decimal_(s) + ); +} + inline double fp(const char *s) { return atof(s); } diff --git a/snesfilter/nall/base64.hpp b/kaijuu/nall/base64.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/base64.hpp rename to kaijuu/nall/base64.hpp diff --git a/kaijuu/nall/bit.hpp b/kaijuu/nall/bit.hpp new file mode 100644 index 00000000..63403eb0 --- /dev/null +++ b/kaijuu/nall/bit.hpp @@ -0,0 +1,82 @@ +#ifndef NALL_BIT_HPP +#define NALL_BIT_HPP + +#include + +namespace nall { + template + inline uintmax_t uclamp(const uintmax_t x) { + enum : uintmax_t { b = 1ull << (bits - 1), y = b * 2 - 1 }; + return y + ((x - y) & -(x < y)); //min(x, y); + } + + template + inline uintmax_t uclip(const uintmax_t x) { + enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; + return (x & m); + } + + template + inline intmax_t sclamp(const intmax_t x) { + enum : intmax_t { b = 1ull << (bits - 1), m = b - 1 }; + return (x > m) ? m : (x < -b) ? -b : x; + } + + template + inline intmax_t sclip(const intmax_t x) { + enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; + return ((x & m) ^ b) - b; + } + + namespace bit { + constexpr inline uintmax_t mask(const char *s, uintmax_t sum = 0) { + return ( + *s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) : + *s == ' ' || *s == '_' ? mask(s + 1, sum) : + *s ? mask(s + 1, sum << 1) : + sum + ); + } + + constexpr inline uintmax_t test(const char *s, uintmax_t sum = 0) { + return ( + *s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) : + *s == ' ' || *s == '_' ? test(s + 1, sum) : + *s ? test(s + 1, sum << 1) : + sum + ); + } + + //lowest(0b1110) == 0b0010 + constexpr inline uintmax_t lowest(const uintmax_t x) { + return x & -x; + } + + //clear_lowest(0b1110) == 0b1100 + constexpr inline uintmax_t clear_lowest(const uintmax_t x) { + return x & (x - 1); + } + + //set_lowest(0b0101) == 0b0111 + constexpr inline uintmax_t set_lowest(const uintmax_t x) { + return x | (x + 1); + } + + //count number of bits set in a byte + inline unsigned count(uintmax_t x) { + unsigned count = 0; + do count += x & 1; while(x >>= 1); + return count; + } + + //round up to next highest single bit: + //round(15) == 16, round(16) == 16, round(17) == 32 + inline uintmax_t round(uintmax_t x) { + if((x & (x - 1)) == 0) return x; + while(x & (x - 1)) x &= x - 1; + return x << 1; + } + } +} + +#endif diff --git a/snesfilter/nall/bmp.hpp b/kaijuu/nall/bmp.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/bmp.hpp rename to kaijuu/nall/bmp.hpp diff --git a/snesfilter/nall/bps/delta.hpp b/kaijuu/nall/bps/delta.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/bps/delta.hpp rename to kaijuu/nall/bps/delta.hpp diff --git a/snesfilter/nall/bps/linear.hpp b/kaijuu/nall/bps/linear.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/bps/linear.hpp rename to kaijuu/nall/bps/linear.hpp diff --git a/snesfilter/nall/bps/metadata.hpp b/kaijuu/nall/bps/metadata.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/bps/metadata.hpp rename to kaijuu/nall/bps/metadata.hpp diff --git a/snesfilter/nall/bps/patch.hpp b/kaijuu/nall/bps/patch.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/bps/patch.hpp rename to kaijuu/nall/bps/patch.hpp diff --git a/snesfilter/nall/compositor.hpp b/kaijuu/nall/compositor.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/compositor.hpp rename to kaijuu/nall/compositor.hpp diff --git a/snesfilter/nall/config.hpp b/kaijuu/nall/config.hpp old mode 100755 new mode 100644 similarity index 76% rename from snesfilter/nall/config.hpp rename to kaijuu/nall/config.hpp index 0c6602df..94be7dc1 --- a/snesfilter/nall/config.hpp +++ b/kaijuu/nall/config.hpp @@ -32,7 +32,7 @@ namespace nall { string desc; type_t type; - string get() const { + inline string get() const { switch(type) { case boolean_t: return { *(bool*)data }; case signed_t: return { *(signed*)data }; @@ -43,7 +43,7 @@ namespace nall { return "???"; } - void set(string s) { + inline void set(string s) { switch(type) { case boolean_t: *(bool*)data = (s == "true"); break; case signed_t: *(signed*)data = integer(s); break; @@ -53,24 +53,27 @@ namespace nall { } } }; - linear_vector list; + vector list; template - void attach(T &data, const char *name, const char *desc = "") { - unsigned n = list.size(); - list[n].data = (uintptr_t)&data; - list[n].name = name; - list[n].desc = desc; - - if(configuration_traits::is_boolean::value) list[n].type = boolean_t; - else if(configuration_traits::is_signed::value) list[n].type = signed_t; - else if(configuration_traits::is_unsigned::value) list[n].type = unsigned_t; - else if(configuration_traits::is_double::value) list[n].type = double_t; - else if(configuration_traits::is_string::value) list[n].type = string_t; - else list[n].type = unknown_t; + inline void append(T &data, const char *name, const char *desc = "") { + item_t item = { (uintptr_t)&data, name, desc }; + if(configuration_traits::is_boolean::value) item.type = boolean_t; + else if(configuration_traits::is_signed::value) item.type = signed_t; + else if(configuration_traits::is_unsigned::value) item.type = unsigned_t; + else if(configuration_traits::is_double::value) item.type = double_t; + else if(configuration_traits::is_string::value) item.type = string_t; + else item.type = unknown_t; + list.append(item); } - virtual bool load(const string &filename) { + //deprecated + template + inline void attach(T &data, const char *name, const char *desc = "") { + append(data, name, desc); + } + + inline virtual bool load(const string &filename) { string data; if(data.readfile(filename) == true) { data.replace("\r", ""); @@ -100,7 +103,7 @@ namespace nall { } } - virtual bool save(const string &filename) const { + inline virtual bool save(const string &filename) const { file fp; if(fp.open(filename, file::mode::write)) { for(unsigned i = 0; i < list.size(); i++) { diff --git a/snesfilter/nall/crc32.hpp b/kaijuu/nall/crc32.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/crc32.hpp rename to kaijuu/nall/crc32.hpp diff --git a/snesfilter/nall/directory.hpp b/kaijuu/nall/directory.hpp old mode 100755 new mode 100644 similarity index 77% rename from snesfilter/nall/directory.hpp rename to kaijuu/nall/directory.hpp index 31ca1e05..4dba2b70 --- a/snesfilter/nall/directory.hpp +++ b/kaijuu/nall/directory.hpp @@ -17,6 +17,8 @@ namespace nall { struct directory { + static bool create(const string &pathname, unsigned permissions = 0755); //recursive + static bool remove(const string &pathname); static bool exists(const string &pathname); static lstring folders(const string &pathname, const string &pattern = "*"); static lstring files(const string &pathname, const string &pattern = "*"); @@ -24,8 +26,27 @@ struct directory { }; #if defined(PLATFORM_WINDOWS) + inline bool directory::create(const string &pathname, unsigned permissions) { + string fullpath = pathname, path; + fullpath.transform("/", "\\"); + fullpath.rtrim<1>("\\"); + lstring pathpart = fullpath.split("\\"); + bool result = false; + for(auto &part : pathpart) { + path.append(part, "\\"); + result = _wmkdir(utf16_t(path)) == 0; + } + return result; + } + + inline bool directory::remove(const string &pathname) { + return _wrmdir(utf16_t(pathname)) == 0; + } + inline bool directory::exists(const string &pathname) { - DWORD result = GetFileAttributes(utf16_t(pathname)); + string name = pathname; + name.trim<1>("\""); + DWORD result = GetFileAttributes(utf16_t(name)); if(result == INVALID_FILE_ATTRIBUTES) return false; return (result & FILE_ATTRIBUTE_DIRECTORY); } @@ -56,7 +77,7 @@ struct directory { } FindClose(handle); } - if(list.size() > 0) sort(&list[0], list.size()); + if(list.size() > 0) list.sort(); for(auto &name : list) name.append("/"); //must append after sorting return list; } @@ -83,7 +104,7 @@ struct directory { } FindClose(handle); } - if(list.size() > 0) sort(&list[0], list.size()); + if(list.size() > 0) list.sort(); return list; } @@ -94,6 +115,21 @@ struct directory { return folders; } #else + inline bool directory::create(const string &pathname, unsigned permissions) { + string fullpath = pathname, path = "/"; + fullpath.trim<1>("/"); + lstring pathpart = fullpath.split("/"); + for(auto &part : pathpart) { + if(!directory::exists(path)) mkdir(path, permissions); + path.append(part, "/"); + } + return mkdir(path, permissions) == 0; + } + + inline bool directory::remove(const string &pathname) { + return rmdir(pathname) == 0; + } + inline bool directory::exists(const string &pathname) { DIR *dp = opendir(pathname); if(!dp) return false; @@ -116,7 +152,7 @@ struct directory { } closedir(dp); } - if(list.size() > 0) sort(&list[0], list.size()); + if(list.size() > 0) list.sort(); for(auto &name : list) name.append("/"); //must append after sorting return list; } @@ -136,7 +172,7 @@ struct directory { } closedir(dp); } - if(list.size() > 0) sort(&list[0], list.size()); + if(list.size() > 0) list.sort(); return list; } diff --git a/snesfilter/nall/dl.hpp b/kaijuu/nall/dl.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dl.hpp rename to kaijuu/nall/dl.hpp diff --git a/snesfilter/nall/dsp.hpp b/kaijuu/nall/dsp.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp.hpp rename to kaijuu/nall/dsp.hpp diff --git a/snesfilter/nall/dsp/buffer.hpp b/kaijuu/nall/dsp/buffer.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp/buffer.hpp rename to kaijuu/nall/dsp/buffer.hpp diff --git a/snesfilter/nall/dsp/core.hpp b/kaijuu/nall/dsp/core.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp/core.hpp rename to kaijuu/nall/dsp/core.hpp diff --git a/snesfilter/nall/dsp/resample/average.hpp b/kaijuu/nall/dsp/resample/average.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp/resample/average.hpp rename to kaijuu/nall/dsp/resample/average.hpp diff --git a/snesfilter/nall/dsp/resample/cosine.hpp b/kaijuu/nall/dsp/resample/cosine.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp/resample/cosine.hpp rename to kaijuu/nall/dsp/resample/cosine.hpp diff --git a/snesfilter/nall/dsp/resample/cubic.hpp b/kaijuu/nall/dsp/resample/cubic.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp/resample/cubic.hpp rename to kaijuu/nall/dsp/resample/cubic.hpp diff --git a/snesfilter/nall/dsp/resample/hermite.hpp b/kaijuu/nall/dsp/resample/hermite.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp/resample/hermite.hpp rename to kaijuu/nall/dsp/resample/hermite.hpp diff --git a/snesfilter/nall/dsp/resample/lib/sinc.hpp b/kaijuu/nall/dsp/resample/lib/sinc.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp/resample/lib/sinc.hpp rename to kaijuu/nall/dsp/resample/lib/sinc.hpp diff --git a/snesfilter/nall/dsp/resample/linear.hpp b/kaijuu/nall/dsp/resample/linear.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp/resample/linear.hpp rename to kaijuu/nall/dsp/resample/linear.hpp diff --git a/snesfilter/nall/dsp/resample/nearest.hpp b/kaijuu/nall/dsp/resample/nearest.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp/resample/nearest.hpp rename to kaijuu/nall/dsp/resample/nearest.hpp diff --git a/snesfilter/nall/dsp/resample/sinc.hpp b/kaijuu/nall/dsp/resample/sinc.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp/resample/sinc.hpp rename to kaijuu/nall/dsp/resample/sinc.hpp diff --git a/snesfilter/nall/dsp/settings.hpp b/kaijuu/nall/dsp/settings.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/dsp/settings.hpp rename to kaijuu/nall/dsp/settings.hpp diff --git a/kaijuu/nall/emulation/famicom.hpp b/kaijuu/nall/emulation/famicom.hpp new file mode 100644 index 00000000..84275d69 --- /dev/null +++ b/kaijuu/nall/emulation/famicom.hpp @@ -0,0 +1,182 @@ +#ifndef NALL_EMULATION_FAMICOM_HPP +#define NALL_EMULATION_FAMICOM_HPP + +#include +#include + +namespace nall { + +struct FamicomCartridge { + string markup; + inline FamicomCartridge(const uint8_t *data, unsigned size); + +//private: + unsigned mapper; + unsigned mirror; + unsigned prgrom; + unsigned prgram; + unsigned chrrom; + unsigned chrram; +}; + +FamicomCartridge::FamicomCartridge(const uint8_t *data, unsigned size) { + markup = ""; + if(size < 16) return; + if(data[0] != 'N') return; + if(data[1] != 'E') return; + if(data[2] != 'S') return; + if(data[3] != 26) return; + + markup.append("\n"); + + mapper = ((data[7] >> 4) << 4) | (data[6] >> 4); + mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01); + prgrom = data[4] * 0x4000; + chrrom = data[5] * 0x2000; + prgram = 0u; + chrram = chrrom == 0u ? 8192u : 0u; + + markup.append("\n"); + + switch(mapper) { + default: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 1: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 2: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 3: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 4: + //MMC3 + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + //MMC6 + //markup.append(" \n"); + //markup.append(" \n"); + //prgram = 1024; + break; + + case 5: + markup.append(" \n"); + markup.append(" \n"); + prgram = 65536; + break; + + case 7: + markup.append(" \n"); + break; + + case 9: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 10: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 16: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 21: + case 23: + case 25: + //VRC4 + markup.append(" \n"); + markup.append(" \n"); + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 22: + //VRC2 + markup.append(" \n"); + markup.append(" \n"); + markup.append(" \n"); + markup.append(" \n"); + break; + + case 24: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 26: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 34: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 66: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 69: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 73: + markup.append(" \n"); + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 75: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 85: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + } + + markup.append(" \n"); + if(prgrom) markup.append(" \n"); + if(prgram) markup.append(" \n"); + markup.append(" \n"); + + markup.append(" \n"); + if(chrrom) markup.append(" \n"); + if(chrram) markup.append(" \n"); + markup.append(" \n"); + + markup.append("\n"); + markup.transform("'", "\""); +} + +} + +#endif diff --git a/kaijuu/nall/emulation/game-boy-advance.hpp b/kaijuu/nall/emulation/game-boy-advance.hpp new file mode 100644 index 00000000..e16d0949 --- /dev/null +++ b/kaijuu/nall/emulation/game-boy-advance.hpp @@ -0,0 +1,68 @@ +#ifndef NALL_EMULATION_GAME_BOY_ADVANCE_HPP +#define NALL_EMULATION_GAME_BOY_ADVANCE_HPP + +#include +#include +#include + +namespace nall { + +struct GameBoyAdvanceCartridge { + string markup; + string identifiers; + inline GameBoyAdvanceCartridge(const uint8_t *data, unsigned size); +}; + +GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t *data, unsigned size) { + struct Identifier { + string name; + unsigned size; + }; + vector idlist; + idlist.append({"SRAM_V", 6}); + idlist.append({"SRAM_F_V", 8}); + idlist.append({"EEPROM_V", 8}); + idlist.append({"FLASH_V", 7}); + idlist.append({"FLASH512_V", 10}); + idlist.append({"FLASH1M_V", 9}); + + lstring list; + for(auto &id : idlist) { + for(signed n = 0; n < size - 16; n++) { + if(!memcmp(data + n, (const char*)id.name, id.size)) { + const char *p = (const char*)data + n + id.size; + if(p[0] >= '0' && p[0] <= '9' + && p[1] >= '0' && p[1] <= '9' + && p[2] >= '0' && p[2] <= '9' + ) { + char text[16]; + memcpy(text, data + n, id.size + 3); + text[id.size + 3] = 0; + list.appendonce(text); + } + } + } + } + identifiers = list.concatenate(","); + + markup = ""; + + markup.append("\n"); + markup.append("\n"); + markup.append(" \n"); + if(0); + else if(identifiers.beginswith("SRAM_V" )) markup.append(" \n"); + else if(identifiers.beginswith("SRAM_F_V" )) markup.append(" \n"); + else if(identifiers.beginswith("EEPROM_V" )) markup.append(" \n"); + else if(identifiers.beginswith("FLASH_V" )) markup.append(" \n"); + else if(identifiers.beginswith("FLASH512_V")) markup.append(" \n"); + else if(identifiers.beginswith("FLASH1M_V" )) markup.append(" \n"); + if(identifiers.empty() == false) markup.append(" \n"); + + markup.append("\n"); + markup.transform("'", "\""); +} + +} + +#endif diff --git a/snesfilter/nall/gameboy/cartridge.hpp b/kaijuu/nall/emulation/game-boy.hpp old mode 100755 new mode 100644 similarity index 85% rename from snesfilter/nall/gameboy/cartridge.hpp rename to kaijuu/nall/emulation/game-boy.hpp index 19ff065d..ef1f3da9 --- a/snesfilter/nall/gameboy/cartridge.hpp +++ b/kaijuu/nall/emulation/game-boy.hpp @@ -1,10 +1,12 @@ -#ifndef NALL_GAMEBOY_CARTRIDGE_HPP -#define NALL_GAMEBOY_CARTRIDGE_HPP +#ifndef NALL_EMULATION_GAME_BOY_HPP +#define NALL_EMULATION_GAME_BOY_HPP + +#include +#include namespace nall { -class GameBoyCartridge { -public: +struct GameBoyCartridge { string markup; inline GameBoyCartridge(uint8_t *data, unsigned size); @@ -18,6 +20,9 @@ public: unsigned romsize; unsigned ramsize; + + bool cgb; + bool cgbonly; } info; }; @@ -48,6 +53,9 @@ GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) { memcpy(romdata, header, 0x8000); } + info.cgb = (romdata[0x0143] & 0x80) == 0x80; + info.cgbonly = (romdata[0x0143] & 0xc0) == 0xc0; + switch(romdata[0x0147]) { case 0x00: info.mapper = "none"; break; case 0x01: info.mapper = "MBC1"; break; @@ -100,15 +108,13 @@ GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) { if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit - markup.append("cartridge mapper=", info.mapper); - if(info.rtc) markup.append(" rtc"); - if(info.rumble) markup.append(" rumble"); - markup.append("\n"); - - markup.append("\t" "rom size=", hex(romsize), "\n"); //TODO: trust/check info.romsize? - - if(info.ramsize > 0) - markup.append("\t" "ram size=", hex(info.ramsize), info.battery ? " non-volatile\n" : "\n"); + markup = "\n"; + markup.append("\n"); + markup.append(" \n"); + markup.append(" \n"); + if(info.ramsize > 0) markup.append(" \n"); + markup.append("\n"); + markup.transform("'", "\""); } } diff --git a/kaijuu/nall/emulation/satellaview.hpp b/kaijuu/nall/emulation/satellaview.hpp new file mode 100644 index 00000000..ddae080c --- /dev/null +++ b/kaijuu/nall/emulation/satellaview.hpp @@ -0,0 +1,26 @@ +#ifndef NALL_EMULATION_SATELLAVIEW_HPP +#define NALL_EMULATION_SATELLAVIEW_HPP + +#include +#include + +namespace nall { + +struct SatellaviewCartridge { + string markup; + inline SatellaviewCartridge(const uint8_t *data, unsigned size); +}; + +SatellaviewCartridge::SatellaviewCartridge(const uint8_t *data, unsigned size) { + markup = ""; + + markup.append("\n"); + markup.append("\n"); + markup.append(" \n"); + markup.append("\n"); + markup.transform("'", "\""); +} + +} + +#endif diff --git a/kaijuu/nall/emulation/sufami-turbo.hpp b/kaijuu/nall/emulation/sufami-turbo.hpp new file mode 100644 index 00000000..0256360c --- /dev/null +++ b/kaijuu/nall/emulation/sufami-turbo.hpp @@ -0,0 +1,33 @@ +#ifndef NALL_EMULATION_SUFAMI_TURBO_HPP +#define NALL_EMULATION_SUFAMI_TURBO_HPP + +#include +#include + +namespace nall { + +struct SufamiTurboCartridge { + string markup; + inline SufamiTurboCartridge(const uint8_t *data, unsigned size); +}; + +SufamiTurboCartridge::SufamiTurboCartridge(const uint8_t *data, unsigned size) { + markup = ""; + + if(size < 0x20000) return; //too small to be a valid game? + if(memcmp(data, "BANDAI SFC-ADX", 14)) return; //missing required header? + unsigned romsize = data[0x36] * 0x20000; //128KB + unsigned ramsize = data[0x37] * 0x800; //2KB + bool linkable = data[0x35] != 0x00; //TODO: unconfirmed + + markup.append("\n"); + markup.append("\n"); + markup.append(" \n"); + markup.append(" \n"); + markup.append("\n"); + markup.transform("'", "\""); +} + +} + +#endif diff --git a/kaijuu/nall/emulation/super-famicom-usart.hpp b/kaijuu/nall/emulation/super-famicom-usart.hpp new file mode 100644 index 00000000..68dea605 --- /dev/null +++ b/kaijuu/nall/emulation/super-famicom-usart.hpp @@ -0,0 +1,103 @@ +#ifndef NALL_EMULATION_SUPER_FAMICOM_USART_HPP +#define NALL_EMULATION_SUPER_FAMICOM_USART_HPP + +#include +#include +#include +#include + +#include +#include +#include + +#define usartproc dllexport + +static nall::function usart_quit; +static nall::function usart_usleep; +static nall::function usart_readable; +static nall::function usart_read; +static nall::function usart_writable; +static nall::function usart_write; + +extern "C" usartproc void usart_init( + nall::function quit, + nall::function usleep, + nall::function readable, + nall::function read, + nall::function writable, + nall::function write +) { + usart_quit = quit; + usart_usleep = usleep; + usart_readable = readable; + usart_read = read; + usart_writable = writable; + usart_write = write; +} + +extern "C" usartproc void usart_main(int, char**); + +// + +static nall::serial usart; +static bool usart_is_virtual = true; +static bool usart_sigint = false; + +static bool usart_virtual() { + return usart_is_virtual; +} + +// + +static bool usarthw_quit() { + return usart_sigint; +} + +static void usarthw_usleep(unsigned milliseconds) { + usleep(milliseconds); +} + +static bool usarthw_readable() { + return usart.readable(); +} + +static uint8_t usarthw_read() { + while(true) { + uint8_t buffer[1]; + signed length = usart.read((uint8_t*)&buffer, 1); + if(length > 0) return buffer[0]; + } +} + +static bool usarthw_writable() { + return usart.writable(); +} + +static void usarthw_write(uint8_t data) { + uint8_t buffer[1] = { data }; + usart.write((uint8_t*)&buffer, 1); +} + +static void sigint(int) { + signal(SIGINT, SIG_DFL); + usart_sigint = true; +} + +int main(int argc, char **argv) { + setpriority(PRIO_PROCESS, 0, -20); //requires superuser privileges; otherwise priority = +0 + signal(SIGINT, sigint); + + if(usart.open("/dev/ttyACM0", 57600, true) == false) { + printf("error: unable to open USART hardware device\n"); + return 0; + } + + usart_is_virtual = false; + usart_init(usarthw_quit, usarthw_usleep, usarthw_readable, usarthw_read, usarthw_writable, usarthw_write); + usart_main(argc, argv); + usart.close(); + + return 0; +} + +#endif diff --git a/kaijuu/nall/emulation/super-famicom.hpp b/kaijuu/nall/emulation/super-famicom.hpp new file mode 100644 index 00000000..597f9893 --- /dev/null +++ b/kaijuu/nall/emulation/super-famicom.hpp @@ -0,0 +1,800 @@ +#ifndef NALL_EMULATION_SUPER_FAMICOM_HPP +#define NALL_EMULATION_SUPER_FAMICOM_HPP + +#include +#include + +namespace nall { + +struct SuperFamicomCartridge { + string markup; + inline SuperFamicomCartridge(const uint8_t *data, unsigned size); + +//private: + inline void read_header(const uint8_t *data, unsigned size); + inline unsigned find_header(const uint8_t *data, unsigned size); + inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr); + + enum HeaderField { + CartName = 0x00, + Mapper = 0x15, + RomType = 0x16, + RomSize = 0x17, + RamSize = 0x18, + CartRegion = 0x19, + Company = 0x1a, + Version = 0x1b, + Complement = 0x1c, //inverse checksum + Checksum = 0x1e, + ResetVector = 0x3c, + }; + + enum Mode { + ModeNormal, + ModeBsxSlotted, + ModeBsx, + ModeSufamiTurbo, + ModeSuperGameBoy, + }; + + enum Type { + TypeNormal, + TypeBsxSlotted, + TypeBsxBios, + TypeBsx, + TypeSufamiTurboBios, + TypeSufamiTurbo, + TypeSuperGameBoy1Bios, + TypeSuperGameBoy2Bios, + TypeGameBoy, + TypeUnknown, + }; + + enum Region { + NTSC, + PAL, + }; + + enum MemoryMapper { + LoROM, + HiROM, + ExLoROM, + ExHiROM, + SuperFXROM, + SA1ROM, + SPC7110ROM, + BSCLoROM, + BSCHiROM, + BSXROM, + STROM, + }; + + enum DSP1MemoryMapper { + DSP1Unmapped, + DSP1LoROM1MB, + DSP1LoROM2MB, + DSP1HiROM, + }; + + bool loaded; //is a base cartridge inserted? + unsigned crc32; //crc32 of all cartridges (base+slot(s)) + unsigned rom_size; + unsigned ram_size; + + Mode mode; + Type type; + Region region; + MemoryMapper mapper; + DSP1MemoryMapper dsp1_mapper; + + bool has_bsx_slot; + bool has_superfx; + bool has_sa1; + bool has_srtc; + bool has_sdd1; + bool has_spc7110; + bool has_spc7110rtc; + bool has_cx4; + bool has_dsp1; + bool has_dsp2; + bool has_dsp3; + bool has_dsp4; + bool has_obc1; + bool has_st010; + bool has_st011; + bool has_st018; +}; + +SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) { + markup = ""; + if(size < 0x8000) return; + + read_header(data, size); + + markup = ""; + if(type == TypeGameBoy) return; + if(type == TypeBsx) return; + if(type == TypeSufamiTurbo) return; + + markup.append("\n"); + + const char *range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? "0000-7fff" : "0000-ffff"; + markup.append("\n"); + + if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + else if(has_cx4) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + else if(has_spc7110) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + else if(has_sdd1) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + else if(mapper == LoROM) { + markup.append( + " \n" + " \n" + " \n" + ); + if(ram_size > 0) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + ); + } + + else if(mapper == HiROM) { + markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + ); + if(ram_size > 0) markup.append( + " \n" + " \n" + " \n" + " \n" + ); + } + + else if(mapper == ExLoROM) { + markup.append( + " \n" + " \n" + " \n" + " \n" + ); + if(ram_size > 0) markup.append( + " \n" + " \n" + " \n" + " \n" + ); + } + + else if(mapper == ExHiROM) { + markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + ); + if(ram_size > 0) markup.append( + " \n" + " \n" + " \n" + " \n" + ); + } + + else if(mapper == SuperFXROM) { + markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + if(ram_size > 0) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + ); + markup.append( + " \n" + ); + } + + else if(mapper == SA1ROM) { + markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + if(ram_size > 0) markup.append( + " \n" + " \n" + " \n" + " \n" + ); + markup.append( + " \n" + ); + } + + else if(mapper == BSCLoROM) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + else if(mapper == BSCHiROM) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + else if(mapper == BSXROM) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + else if(mapper == STROM) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + if(has_spc7110rtc) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + if(has_srtc) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + if(has_obc1) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + if(has_dsp1) { + //91e87d11e1c30d172556bed2211cce2efa94ba595f58c5d264809ef4d363a97b dsp1.rom + markup.append( + " \n" + " \n" + ); + if(dsp1_mapper == DSP1LoROM1MB) markup.append( + " \n" + " \n" + " \n" + " \n" + ); + if(dsp1_mapper == DSP1LoROM2MB) markup.append( + " \n" + " \n" + " \n" + " \n" + ); + if(dsp1_mapper == DSP1HiROM) markup.append( + " \n" + " \n" + " \n" + " \n" + ); + markup.append( + " \n" + ); + } + + if(has_dsp2) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + if(has_dsp3) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + if(has_dsp4) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + if(has_st010) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + if(has_st011) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + if(has_st018) markup.append( + " \n" + " \n" + " \n" + " \n" + " \n" + ); + + markup.append("\n"); + markup.transform("'", "\""); +} + +void SuperFamicomCartridge::read_header(const uint8_t *data, unsigned size) { + type = TypeUnknown; + mapper = LoROM; + dsp1_mapper = DSP1Unmapped; + region = NTSC; + rom_size = size; + ram_size = 0; + + has_bsx_slot = false; + has_superfx = false; + has_sa1 = false; + has_srtc = false; + has_sdd1 = false; + has_spc7110 = false; + has_spc7110rtc = false; + has_cx4 = false; + has_dsp1 = false; + has_dsp2 = false; + has_dsp3 = false; + has_dsp4 = false; + has_obc1 = false; + has_st010 = false; + has_st011 = false; + has_st018 = false; + + //===================== + //detect Game Boy carts + //===================== + + if(size >= 0x0140) { + if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66 + && data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) { + type = TypeGameBoy; + return; + } + } + + if(size < 32768) { + type = TypeUnknown; + return; + } + + const unsigned index = find_header(data, size); + const uint8_t mapperid = data[index + Mapper]; + const uint8_t rom_type = data[index + RomType]; + const uint8_t rom_size = data[index + RomSize]; + const uint8_t company = data[index + Company]; + const uint8_t regionid = data[index + CartRegion] & 0x7f; + + ram_size = 1024 << (data[index + RamSize] & 7); + if(ram_size == 1024) ram_size = 0; //no RAM present + + //0, 1, 13 = NTSC; 2 - 12 = PAL + region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL; + + //======================= + //detect BS-X flash carts + //======================= + + if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) { + if(data[index + 0x14] == 0x00) { + const uint8_t n15 = data[index + 0x15]; + if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) { + if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) { + type = TypeBsx; + mapper = BSXROM; + region = NTSC; //BS-X only released in Japan + return; + } + } + } + } + + //========================= + //detect Sufami Turbo carts + //========================= + + if(!memcmp(data, "BANDAI SFC-ADX", 14)) { + if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) { + type = TypeSufamiTurboBios; + } else { + type = TypeSufamiTurbo; + } + mapper = STROM; + region = NTSC; //Sufami Turbo only released in Japan + return; //RAM size handled outside this routine + } + + //========================== + //detect Super Game Boy BIOS + //========================== + + if(!memcmp(data + index, "Super GAMEBOY2", 14)) { + type = TypeSuperGameBoy2Bios; + return; + } + + if(!memcmp(data + index, "Super GAMEBOY", 13)) { + type = TypeSuperGameBoy1Bios; + return; + } + + //===================== + //detect standard carts + //===================== + + //detect presence of BS-X flash cartridge connector (reads extended header information) + if(data[index - 14] == 'Z') { + if(data[index - 11] == 'J') { + uint8_t n13 = data[index - 13]; + if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) { + if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) { + has_bsx_slot = true; + } + } + } + } + + if(has_bsx_slot) { + if(!memcmp(data + index, "Satellaview BS-X ", 21)) { + //BS-X base cart + type = TypeBsxBios; + mapper = BSXROM; + region = NTSC; //BS-X only released in Japan + return; //RAM size handled internally by load_cart_bsx() -> BSXCart class + } else { + type = TypeBsxSlotted; + mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM); + region = NTSC; //BS-X slotted cartridges only released in Japan + } + } else { + //standard cart + type = TypeNormal; + + if(index == 0x7fc0 && size >= 0x401000) { + mapper = ExLoROM; + } else if(index == 0x7fc0 && mapperid == 0x32) { + mapper = ExLoROM; + } else if(index == 0x7fc0) { + mapper = LoROM; + } else if(index == 0xffc0) { + mapper = HiROM; + } else { //index == 0x40ffc0 + mapper = ExHiROM; + } + } + + if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) { + has_superfx = true; + mapper = SuperFXROM; + ram_size = 1024 << (data[index - 3] & 7); + if(ram_size == 1024) ram_size = 0; + } + + if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) { + has_sa1 = true; + mapper = SA1ROM; + } + + if(mapperid == 0x35 && rom_type == 0x55) { + has_srtc = true; + } + + if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) { + has_sdd1 = true; + } + + if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) { + has_spc7110 = true; + has_spc7110rtc = (rom_type == 0xf9); + mapper = SPC7110ROM; + } + + if(mapperid == 0x20 && rom_type == 0xf3) { + has_cx4 = true; + } + + if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) { + has_dsp1 = true; + } + + if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) { + has_dsp1 = true; + } + + if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) { + has_dsp1 = true; + } + + if(has_dsp1 == true) { + if((mapperid & 0x2f) == 0x20 && size <= 0x100000) { + dsp1_mapper = DSP1LoROM1MB; + } else if((mapperid & 0x2f) == 0x20) { + dsp1_mapper = DSP1LoROM2MB; + } else if((mapperid & 0x2f) == 0x21) { + dsp1_mapper = DSP1HiROM; + } + } + + if(mapperid == 0x20 && rom_type == 0x05) { + has_dsp2 = true; + } + + if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) { + has_dsp3 = true; + } + + if(mapperid == 0x30 && rom_type == 0x03) { + has_dsp4 = true; + } + + if(mapperid == 0x30 && rom_type == 0x25) { + has_obc1 = true; + } + + if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) { + has_st010 = true; + } + + if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) { + has_st011 = true; + } + + if(mapperid == 0x30 && rom_type == 0xf5) { + has_st018 = true; + } +} + +unsigned SuperFamicomCartridge::find_header(const uint8_t *data, unsigned size) { + unsigned score_lo = score_header(data, size, 0x007fc0); + unsigned score_hi = score_header(data, size, 0x00ffc0); + unsigned score_ex = score_header(data, size, 0x40ffc0); + if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits + + if(score_lo >= score_hi && score_lo >= score_ex) { + return 0x007fc0; + } else if(score_hi >= score_ex) { + return 0x00ffc0; + } else { + return 0x40ffc0; + } +} + +unsigned SuperFamicomCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) { + if(size < addr + 64) return 0; //image too small to contain header at this location? + int score = 0; + + uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8); + uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8); + uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8); + + uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset + uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit + + //$00:[000-7fff] contains uninitialized RAM and MMIO. + //reset vector must point to ROM at $00:[8000-ffff] to be considered valid. + if(resetvector < 0x8000) return 0; + + //some images duplicate the header in multiple locations, and others have completely + //invalid header information that cannot be relied upon. + //below code will analyze the first opcode executed at the specified reset vector to + //determine the probability that this is the correct header. + + //most likely opcodes + if(resetop == 0x78 //sei + || resetop == 0x18 //clc (clc; xce) + || resetop == 0x38 //sec (sec; xce) + || resetop == 0x9c //stz $nnnn (stz $4200) + || resetop == 0x4c //jmp $nnnn + || resetop == 0x5c //jml $nnnnnn + ) score += 8; + + //plausible opcodes + if(resetop == 0xc2 //rep #$nn + || resetop == 0xe2 //sep #$nn + || resetop == 0xad //lda $nnnn + || resetop == 0xae //ldx $nnnn + || resetop == 0xac //ldy $nnnn + || resetop == 0xaf //lda $nnnnnn + || resetop == 0xa9 //lda #$nn + || resetop == 0xa2 //ldx #$nn + || resetop == 0xa0 //ldy #$nn + || resetop == 0x20 //jsr $nnnn + || resetop == 0x22 //jsl $nnnnnn + ) score += 4; + + //implausible opcodes + if(resetop == 0x40 //rti + || resetop == 0x60 //rts + || resetop == 0x6b //rtl + || resetop == 0xcd //cmp $nnnn + || resetop == 0xec //cpx $nnnn + || resetop == 0xcc //cpy $nnnn + ) score -= 4; + + //least likely opcodes + if(resetop == 0x00 //brk #$nn + || resetop == 0x02 //cop #$nn + || resetop == 0xdb //stp + || resetop == 0x42 //wdm + || resetop == 0xff //sbc $nnnnnn,x + ) score -= 8; + + //at times, both the header and reset vector's first opcode will match ... + //fallback and rely on info validity in these cases to determine more likely header. + + //a valid checksum is the biggest indicator of a valid header. + if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4; + + if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM + if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM + if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually ExLoROM + if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM + + if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header + if(data[addr + RomType] < 0x08) score++; + if(data[addr + RomSize] < 0x10) score++; + if(data[addr + RamSize] < 0x08) score++; + if(data[addr + CartRegion] < 14) score++; + + if(score < 0) score = 0; + return score; +} + +} + +#endif diff --git a/snesfilter/nall/endian.hpp b/kaijuu/nall/endian.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/endian.hpp rename to kaijuu/nall/endian.hpp diff --git a/snesfilter/nall/file.hpp b/kaijuu/nall/file.hpp old mode 100755 new mode 100644 similarity index 81% rename from snesfilter/nall/file.hpp rename to kaijuu/nall/file.hpp index 8447f3ab..8a751041 --- a/snesfilter/nall/file.hpp +++ b/kaijuu/nall/file.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace nall { inline FILE* fopen_utf8(const string &utf8_filename, const char *mode) { @@ -16,25 +17,61 @@ namespace nall { #endif } - class file { - public: - enum class mode : unsigned { read, write, readwrite, writeread }; + struct file { + enum class mode : unsigned { read, write, modify, append, readwrite = modify, writeread = append }; enum class index : unsigned { absolute, relative }; enum class time : unsigned { create, modify, access }; - static bool read(const string &filename, uint8_t *&data, unsigned &size) { - data = 0; - file fp; - if(fp.open(filename, mode::read) == false) return false; - size = fp.size(); - data = new uint8_t[size]; - fp.read(data, size); - fp.close(); + static bool copy(const string &sourcename, const string &targetname) { + file rd, wr; + if(rd.open(sourcename, mode::read) == false) return false; + if(wr.open(targetname, mode::write) == false) return false; + for(unsigned n = 0; n < rd.size(); n++) wr.write(rd.read()); return true; } - static bool read(const string &filename, const uint8_t *&data, unsigned &size) { - return file::read(filename, (uint8_t*&)data, size); + static bool move(const string &sourcename, const string &targetname) { + #if !defined(_WIN32) + return rename(sourcename, targetname) == 0; + #else + return _wrename(utf16_t(sourcename), utf16_t(targetname)) == 0; + #endif + } + + static bool remove(const string &filename) { + return unlink(filename) == 0; + } + + static bool truncate(const string &filename, unsigned size) { + #if !defined(_WIN32) + return truncate(filename, size) == 0; + #else + bool result = false; + FILE *fp = fopen(filename, "rb+"); + if(fp) { + result = _chsize(fileno(fp), size) == 0; + fclose(fp); + } + return result; + #endif + } + + static vector read(const string &filename) { + vector memory; + file fp; + if(fp.open(filename, mode::read)) { + memory.resize(fp.size()); + fp.read(memory.data(), memory.size()); + } + return memory; + } + + static bool read(const string &filename, uint8_t *data, unsigned size) { + file fp; + if(fp.open(filename, mode::read) == false) return false; + fp.read(data, size); + fp.close(); + return true; } static bool write(const string &filename, const uint8_t *data, unsigned size) { @@ -134,13 +171,13 @@ namespace nall { file_offset = req_offset; } - int offset() { - if(!fp) return -1; //file not open + unsigned offset() const { + if(!fp) return 0; //file not open return file_offset; } - int size() { - if(!fp) return -1; //file not open + unsigned size() const { + if(!fp) return 0; //file not open return file_size; } @@ -194,7 +231,7 @@ namespace nall { } } - bool open() { + bool open() const { return fp; } @@ -232,7 +269,7 @@ namespace nall { file() { memset(buffer, 0, sizeof buffer); - buffer_offset = -1; + buffer_offset = -1; //invalidate buffer buffer_dirty = false; fp = 0; file_offset = 0; diff --git a/snesfilter/nall/filemap.hpp b/kaijuu/nall/filemap.hpp old mode 100755 new mode 100644 similarity index 99% rename from snesfilter/nall/filemap.hpp rename to kaijuu/nall/filemap.hpp index 7eeac2b0..f57d933c --- a/snesfilter/nall/filemap.hpp +++ b/kaijuu/nall/filemap.hpp @@ -1,6 +1,7 @@ #ifndef NALL_FILEMAP_HPP #define NALL_FILEMAP_HPP +#include #include #include diff --git a/snesfilter/nall/function.hpp b/kaijuu/nall/function.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/function.hpp rename to kaijuu/nall/function.hpp diff --git a/snesfilter/nall/gzip.hpp b/kaijuu/nall/gzip.hpp old mode 100755 new mode 100644 similarity index 83% rename from snesfilter/nall/gzip.hpp rename to kaijuu/nall/gzip.hpp index 8f5d206b..a72a3faf --- a/snesfilter/nall/gzip.hpp +++ b/kaijuu/nall/gzip.hpp @@ -11,20 +11,18 @@ struct gzip { uint8_t *data; unsigned size; - bool decompress(const string &filename); - bool decompress(const uint8_t *data, unsigned size); + inline bool decompress(const string &filename); + inline bool decompress(const uint8_t *data, unsigned size); - gzip(); - ~gzip(); + inline gzip(); + inline ~gzip(); }; bool gzip::decompress(const string &filename) { - uint8_t *data; - unsigned size; - if(file::read(filename, data, size) == false) return false; - bool result = decompress(data, size); - delete[] data; - return result; + if(auto memory = file::read(filename)) { + return decompress(memory.data(), memory.size()); + } + return false; } bool gzip::decompress(const uint8_t *data, unsigned size) { diff --git a/snesfilter/nall/http.hpp b/kaijuu/nall/http.hpp old mode 100755 new mode 100644 similarity index 99% rename from snesfilter/nall/http.hpp rename to kaijuu/nall/http.hpp index 1b2eab4f..48aeb097 --- a/snesfilter/nall/http.hpp +++ b/kaijuu/nall/http.hpp @@ -7,9 +7,9 @@ #include #include #else - #include #include #include + #include #endif #include @@ -117,7 +117,7 @@ struct http { } } } else if(auto position = header.iposition("\r\nContent-Length: ")) { - unsigned length = decimal((const char*)header + position() + 16); + unsigned length = decimal((const char*)header + position() + 18); while(length) { char buffer[256]; int packetlength = recv(serversocket, buffer, min(256, length), 0); diff --git a/snesfilter/nall/image.hpp b/kaijuu/nall/image.hpp old mode 100755 new mode 100644 similarity index 75% rename from snesfilter/nall/image.hpp rename to kaijuu/nall/image.hpp index c79655eb..552a3e30 --- a/snesfilter/nall/image.hpp +++ b/kaijuu/nall/image.hpp @@ -2,6 +2,7 @@ #define NALL_IMAGE_HPP #include +#include #include #include #include @@ -35,14 +36,21 @@ struct image { inline image(const image &source); inline image(image &&source); inline image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask); + inline image(const string &filename); + inline image(const uint8_t *data, unsigned size); + inline image(); inline ~image(); inline uint64_t read(const uint8_t *data) const; inline void write(uint8_t *data, uint64_t value) const; inline void free(); + inline bool empty() const; inline void allocate(unsigned width, unsigned height); + inline void clear(uint64_t color); inline bool load(const string &filename); +//inline bool loadBMP(const uint8_t *data, unsigned size); + inline bool loadPNG(const uint8_t *data, unsigned size); inline void scale(unsigned width, unsigned height, interpolation op); inline void transform(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask); inline void alphaBlend(uint64_t alphaColor); @@ -141,6 +149,52 @@ image::image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask); } +image::image(const string &filename) : data(nullptr) { + width = 0, height = 0, pitch = 0; + + this->endian = 0; + this->depth = 32; + this->stride = 4; + + alpha.mask = 255u << 24, red.mask = 255u << 16, green.mask = 255u << 8, blue.mask = 255u << 0; + alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask); + red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask); + green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask); + blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask); + + load(filename); +} + +image::image(const uint8_t *data, unsigned size) : data(nullptr) { + width = 0, height = 0, pitch = 0; + + this->endian = 0; + this->depth = 32; + this->stride = 4; + + alpha.mask = 255u << 24, red.mask = 255u << 16, green.mask = 255u << 8, blue.mask = 255u << 0; + alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask); + red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask); + green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask); + blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask); + + loadPNG(data, size); +} + +image::image() : data(nullptr) { + width = 0, height = 0, pitch = 0; + + this->endian = 0; + this->depth = 32; + this->stride = 4; + + alpha.mask = 255u << 24, red.mask = 255u << 16, green.mask = 255u << 8, blue.mask = 255u << 0; + alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask); + red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask); + green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask); + blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask); +} + image::~image() { free(); } @@ -168,7 +222,14 @@ void image::free() { data = nullptr; } +bool image::empty() const { + if(data == nullptr) return true; + if(width == 0 || height == 0) return true; + return false; +} + void image::allocate(unsigned width, unsigned height) { + if(data != nullptr && this->width == width && this->height == height) return; free(); data = new uint8_t[width * height * stride](); pitch = width * stride; @@ -176,6 +237,14 @@ void image::allocate(unsigned width, unsigned height) { this->height = height; } +void image::clear(uint64_t color) { + uint8_t *dp = data; + for(unsigned n = 0; n < width * height; n++) { + write(dp, color); + dp += stride; + } +} + bool image::load(const string &filename) { if(loadBMP(filename) == true) return true; if(loadPNG(filename) == true) return true; @@ -183,8 +252,8 @@ bool image::load(const string &filename) { } void image::scale(unsigned outputWidth, unsigned outputHeight, interpolation op) { - scaleX(outputWidth, op); - scaleY(outputHeight, op); + if(width != outputWidth) scaleX(outputWidth, op); + if(height != outputHeight) scaleY(outputHeight, op); } void image::transform(bool outputEndian, unsigned outputDepth, uint64_t outputAlphaMask, uint64_t outputRedMask, uint64_t outputGreenMask, uint64_t outputBlueMask) { @@ -209,7 +278,7 @@ void image::transform(bool outputEndian, unsigned outputDepth, uint64_t outputAl g = normalize(g, green.depth, output.green.depth); b = normalize(b, blue.depth, output.blue.depth); - output.write(dp, (a << output.alpha.shift) + (r << output.red.shift) + (g << output.green.shift) + (b << output.blue.shift)); + output.write(dp, (a << output.alpha.shift) | (r << output.red.shift) | (g << output.green.shift) | (b << output.blue.shift)); dp += output.stride; } } @@ -239,7 +308,7 @@ void image::alphaBlend(uint64_t alphaColor) { colorG = (colorG * alphaScale) + (alphaG * (1.0 - alphaScale)); colorB = (colorB * alphaScale) + (alphaB * (1.0 - alphaScale)); - write(dp, (colorA << alpha.shift) + (colorR << red.shift) + (colorG << green.shift) + (colorB << blue.shift)); + write(dp, (colorA << alpha.shift) | (colorR << red.shift) | (colorG << green.shift) | (colorB << blue.shift)); dp += stride; } } @@ -267,13 +336,14 @@ uint64_t image::interpolate(double mu, const uint64_t *s, double (*op)(double, d G = max(0, min(G, (1 << green.depth) - 1)); B = max(0, min(B, (1 << blue.depth) - 1)); - return (A << alpha.shift) + (R << red.shift) + (G << green.shift) + (B << blue.shift); + return (A << alpha.shift) | (R << red.shift) | (G << green.shift) | (B << blue.shift); } void image::scaleX(unsigned outputWidth, interpolation op) { uint8_t *outputData = new uint8_t[outputWidth * height * stride]; unsigned outputPitch = outputWidth * stride; double step = (double)width / (double)outputWidth; + const uint8_t *terminal = data + pitch * height; #pragma omp parallel for for(unsigned y = 0; y < height; y++) { @@ -281,15 +351,12 @@ void image::scaleX(unsigned outputWidth, interpolation op) { uint8_t *sp = data + pitch * y; double fraction = 0.0; - uint64_t s[4] = { read(sp), read(sp), read(sp), read(sp) }; + uint64_t s[4] = { sp < terminal ? read(sp) : 0 }; //B,C (0,1) = center of kernel { 0, 0, 1, 2 } + s[1] = s[0]; + s[2] = sp + stride < terminal ? read(sp += stride) : s[1]; + s[3] = sp + stride < terminal ? read(sp += stride) : s[2]; for(unsigned x = 0; x < width; x++) { - if(sp >= data + pitch * height) break; - s[0] = s[1]; - s[1] = s[2]; - s[2] = s[3]; - s[3] = read(sp); - while(fraction <= 1.0) { if(dp >= outputData + outputPitch * height) break; write(dp, interpolate(fraction, (const uint64_t*)&s, op)); @@ -297,7 +364,8 @@ void image::scaleX(unsigned outputWidth, interpolation op) { fraction += step; } - sp += stride; + s[0] = s[1]; s[1] = s[2]; s[2] = s[3]; + if(sp + stride < terminal) s[3] = read(sp += stride); fraction -= 1.0; } } @@ -311,6 +379,7 @@ void image::scaleX(unsigned outputWidth, interpolation op) { void image::scaleY(unsigned outputHeight, interpolation op) { uint8_t *outputData = new uint8_t[width * outputHeight * stride]; double step = (double)height / (double)outputHeight; + const uint8_t *terminal = data + pitch * height; #pragma omp parallel for for(unsigned x = 0; x < width; x++) { @@ -318,15 +387,12 @@ void image::scaleY(unsigned outputHeight, interpolation op) { uint8_t *sp = data + stride * x; double fraction = 0.0; - uint64_t s[4] = { read(sp), read(sp), read(sp), read(sp) }; + uint64_t s[4] = { sp < terminal ? read(sp) : 0 }; + s[1] = s[0]; + s[2] = sp + pitch < terminal ? read(sp += pitch) : s[1]; + s[3] = sp + pitch < terminal ? read(sp += pitch) : s[2]; for(unsigned y = 0; y < height; y++) { - if(sp >= data + pitch * height) break; - s[0] = s[1]; - s[1] = s[2]; - s[2] = s[3]; - s[3] = read(sp); - while(fraction <= 1.0) { if(dp >= outputData + pitch * outputHeight) break; write(dp, interpolate(fraction, (const uint64_t*)&s, op)); @@ -334,7 +400,8 @@ void image::scaleY(unsigned outputHeight, interpolation op) { fraction += step; } - sp += pitch; + s[0] = s[1]; s[1] = s[2]; s[2] = s[3]; + if(sp + pitch < terminal) s[3] = read(sp += pitch); fraction -= 1.0; } } @@ -360,7 +427,7 @@ bool image::loadBMP(const string &filename) { uint64_t r = normalize((uint8_t)(color >> 16), 8, red.depth); uint64_t g = normalize((uint8_t)(color >> 8), 8, green.depth); uint64_t b = normalize((uint8_t)(color >> 0), 8, blue.depth); - write(dp, (a << alpha.shift) + (r << red.shift) + (g << green.shift) + (b << blue.shift)); + write(dp, (a << alpha.shift) | (r << red.shift) | (g << green.shift) | (b << blue.shift)); dp += stride; } } @@ -369,9 +436,9 @@ bool image::loadBMP(const string &filename) { return true; } -bool image::loadPNG(const string &filename) { +bool image::loadPNG(const uint8_t *pngData, unsigned pngSize) { png source; - if(source.decode(filename) == false) return false; + if(source.decode(pngData, pngSize) == false) return false; allocate(source.info.width, source.info.height); const uint8_t *sp = source.data; @@ -415,7 +482,7 @@ bool image::loadPNG(const string &filename) { g = normalize(g, source.info.bitDepth, green.depth); b = normalize(b, source.info.bitDepth, blue.depth); - return (a << alpha.shift) + (r << red.shift) + (g << green.shift) + (b << blue.shift); + return (a << alpha.shift) | (r << red.shift) | (g << green.shift) | (b << blue.shift); }; for(unsigned y = 0; y < height; y++) { @@ -428,6 +495,12 @@ bool image::loadPNG(const string &filename) { return true; } +bool image::loadPNG(const string &filename) { + filemap map; + if(map.open(filename, filemap::mode::read) == false) return false; + return loadPNG(map.data(), map.size()); +} + } #endif diff --git a/snesfilter/nall/inflate.hpp b/kaijuu/nall/inflate.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/inflate.hpp rename to kaijuu/nall/inflate.hpp diff --git a/snesfilter/nall/input.hpp b/kaijuu/nall/input.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/input.hpp rename to kaijuu/nall/input.hpp diff --git a/snesfilter/nall/interpolation.hpp b/kaijuu/nall/interpolation.hpp old mode 100755 new mode 100644 similarity index 91% rename from snesfilter/nall/interpolation.hpp rename to kaijuu/nall/interpolation.hpp index 46a09a49..afc7108b --- a/snesfilter/nall/interpolation.hpp +++ b/kaijuu/nall/interpolation.hpp @@ -5,23 +5,23 @@ namespace nall { struct Interpolation { static inline double Nearest(double mu, double a, double b, double c, double d) { - return (mu < 0.5 ? c : d); + return (mu <= 0.5 ? b : c); } static inline double Sublinear(double mu, double a, double b, double c, double d) { mu = ((mu - 0.5) * 2.0) + 0.5; if(mu < 0) mu = 0; if(mu > 1) mu = 1; - return c * (1.0 - mu) + d * mu; + return b * (1.0 - mu) + c * mu; } static inline double Linear(double mu, double a, double b, double c, double d) { - return c * (1.0 - mu) + d * mu; + return b * (1.0 - mu) + c * mu; } static inline double Cosine(double mu, double a, double b, double c, double d) { mu = (1.0 - cos(mu * 3.14159265)) / 2.0; - return c * (1.0 - mu) + d * mu; + return b * (1.0 - mu) + c * mu; } static inline double Cubic(double mu, double a, double b, double c, double d) { diff --git a/snesfilter/nall/intrinsics.hpp b/kaijuu/nall/intrinsics.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/intrinsics.hpp rename to kaijuu/nall/intrinsics.hpp diff --git a/kaijuu/nall/invoke.hpp b/kaijuu/nall/invoke.hpp new file mode 100644 index 00000000..9dfb7d0b --- /dev/null +++ b/kaijuu/nall/invoke.hpp @@ -0,0 +1,52 @@ +#ifndef NALL_INVOKE_HPP +#define NALL_INVOKE_HPP + +//void invoke(const string &name, const string& args...); +//if a program is specified, it is executed with the arguments provided +//if a file is specified, the file is opened using the program associated with said file type +//if a folder is specified, the folder is opened using the associated file explorer +//if a URL is specified, the default web browser is opened and pointed at the URL requested +//path environment variable is always consulted +//execution is asynchronous (non-blocking); use system() for synchronous execution + +#include +#ifdef _WIN32 + #include +#endif + +namespace nall { + +#ifdef _WIN32 + +template +inline void invoke(const string &name, Args&&... args) { + lstring argl(std::forward(args)...); + for(auto &arg : argl) if(arg.position(" ")) arg = {"\"", arg, "\""}; + string arguments = argl.concatenate(" "); + ShellExecuteW(NULL, NULL, utf16_t(name), utf16_t(arguments), NULL, SW_SHOWNORMAL); +} + +#else + +template +inline void invoke(const string &name, Args&&... args) { + pid_t pid = fork(); + if(pid == 0) { + const char *argv[1 + sizeof...(args) + 1], **argp = argv; + lstring argl(std::forward(args)...); + *argp++ = (const char*)name; + for(auto &arg : argl) *argp++ = (const char*)arg; + *argp++ = nullptr; + + if(execvp(name, (char* const*)argv) < 0) { + execlp("xdg-open", "xdg-open", (const char*)name, nullptr); + } + exit(0); + } +} + +#endif + +} + +#endif diff --git a/snesfilter/nall/ips.hpp b/kaijuu/nall/ips.hpp old mode 100755 new mode 100644 similarity index 89% rename from snesfilter/nall/ips.hpp rename to kaijuu/nall/ips.hpp index 3071d038..473d74c5 --- a/snesfilter/nall/ips.hpp +++ b/kaijuu/nall/ips.hpp @@ -11,8 +11,6 @@ struct ips { inline bool apply(); inline void source(const uint8_t *data, unsigned size); inline void modify(const uint8_t *data, unsigned size); - inline bool source(const string &filename); - inline bool modify(const string &filename); inline ips(); inline ~ips(); @@ -88,14 +86,6 @@ void ips::modify(const uint8_t *data, unsigned size) { modifyData = data, modifySize = size; } -bool ips::source(const string &filename) { - return file::read(filename, sourceData, sourceSize); -} - -bool ips::modify(const string &filename) { - return file::read(filename, modifyData, modifySize); -} - ips::ips() : data(nullptr), sourceData(nullptr), modifyData(nullptr) { } diff --git a/snesfilter/nall/lzss.hpp b/kaijuu/nall/lzss.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/lzss.hpp rename to kaijuu/nall/lzss.hpp diff --git a/kaijuu/nall/map.hpp b/kaijuu/nall/map.hpp new file mode 100644 index 00000000..938f0c2d --- /dev/null +++ b/kaijuu/nall/map.hpp @@ -0,0 +1,117 @@ +#ifndef NALL_MAP_HPP +#define NALL_MAP_HPP + +#include + +namespace nall { + +template +struct map { + struct pair { + LHS name; + RHS data; + }; + + inline void reset() { + list.reset(); + } + + inline unsigned size() const { + return list.size(); + } + + //O(log n) find + inline optional find(const LHS &name) const { + signed first = 0, last = size() - 1; + while(first <= last) { + signed middle = (first + last) / 2; + if(name < list[middle].name) last = middle - 1; //search lower half + else if(list[middle].name < name) first = middle + 1; //search upper half + else return { true, (unsigned)middle }; //match found + } + return { false, 0u }; + } + + //O(n) insert + O(log n) find + inline RHS& insert(const LHS &name, const RHS &data) { + if(auto position = find(name)) { + list[position()].data = data; + return list[position()].data; + } + signed offset = size(); + for(unsigned n = 0; n < size(); n++) { + if(name < list[n].name) { offset = n; break; } + } + list.insert(offset, { name, data }); + return list[offset].data; + } + + //O(log n) find + inline void modify(const LHS &name, const RHS &data) { + if(auto position = find(name)) list[position()].data = data; + } + + //O(n) remove + O(log n) find + inline void remove(const LHS &name) { + if(auto position = find(name)) list.remove(position()); + } + + //O(log n) find + inline RHS& operator[](const LHS &name) { + if(auto position = find(name)) return list[position()].data; + throw; + } + + inline const RHS& operator[](const LHS &name) const { + if(auto position = find(name)) return list[position()].data; + throw; + } + + inline RHS& operator()(const LHS &name) { + if(auto position = find(name)) return list[position()].data; + return insert(name, RHS()); + } + + inline const RHS& operator()(const LHS &name, const RHS &data) const { + if(auto position = find(name)) return list[position()].data; + return data; + } + + inline pair* begin() { return list.begin(); } + inline pair* end() { return list.end(); } + inline const pair* begin() const { return list.begin(); } + inline const pair* end() const { return list.end(); } + +protected: + vector list; +}; + +template +struct bidirectional_map { + const map &lhs; + const map &rhs; + + inline void reset() { + llist.reset(); + rlist.reset(); + } + + inline unsigned size() const { + return llist.size(); + } + + inline void insert(const LHS &ldata, const RHS &rdata) { + llist.insert(ldata, rdata); + rlist.insert(rdata, ldata); + } + + inline bidirectional_map() : lhs(llist), rhs(rlist) {} + +protected: + map llist; + map rlist; +}; + +} + +#endif diff --git a/kaijuu/nall/mosaic.hpp b/kaijuu/nall/mosaic.hpp new file mode 100644 index 00000000..16fd0bfd --- /dev/null +++ b/kaijuu/nall/mosaic.hpp @@ -0,0 +1,10 @@ +#ifndef NALL_MOSAIC_HPP +#define NALL_MOSAIC_HPP + +#define NALL_MOSAIC_INTERNAL_HPP +#include +#include +#include +#undef NALL_MOSAIC_INTERNAL_HPP + +#endif diff --git a/kaijuu/nall/mosaic/bitstream.hpp b/kaijuu/nall/mosaic/bitstream.hpp new file mode 100644 index 00000000..e2cb3bc5 --- /dev/null +++ b/kaijuu/nall/mosaic/bitstream.hpp @@ -0,0 +1,55 @@ +#ifdef NALL_MOSAIC_INTERNAL_HPP + +namespace nall { +namespace mosaic { + +struct bitstream { + filemap fp; + uint8_t *data; + unsigned size; + bool readonly; + bool endian; + + inline bool read(uint64_t addr) const { + if(data == nullptr || (addr >> 3) >= size) return 0; + unsigned mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7)); + return data[addr >> 3] & mask; + } + + inline void write(uint64_t addr, bool value) { + if(data == nullptr || readonly == true || (addr >> 3) >= size) return; + unsigned mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7)); + if(value == 0) data[addr >> 3] &= ~mask; + if(value == 1) data[addr >> 3] |= mask; + } + + inline bool open(const string &filename) { + readonly = false; + if(fp.open(filename, filemap::mode::readwrite) == false) { + readonly = true; + if(fp.open(filename, filemap::mode::read) == false) { + return false; + } + } + data = fp.data(); + size = fp.size(); + return true; + } + + inline void close() { + fp.close(); + data = nullptr; + } + + inline bitstream() : data(nullptr), endian(1) { + } + + inline ~bitstream() { + close(); + } +}; + +} +} + +#endif diff --git a/kaijuu/nall/mosaic/context.hpp b/kaijuu/nall/mosaic/context.hpp new file mode 100644 index 00000000..bc7a518a --- /dev/null +++ b/kaijuu/nall/mosaic/context.hpp @@ -0,0 +1,224 @@ +#ifdef NALL_MOSAIC_INTERNAL_HPP + +namespace nall { +namespace mosaic { + +struct context { + unsigned offset; + unsigned width; + unsigned height; + unsigned count; + + bool endian; //0 = lsb, 1 = msb + bool order; //0 = linear, 1 = planar + unsigned depth; //1 - 24bpp + + unsigned blockWidth; + unsigned blockHeight; + unsigned blockStride; + unsigned blockOffset; + vector block; + + unsigned tileWidth; + unsigned tileHeight; + unsigned tileStride; + unsigned tileOffset; + vector tile; + + unsigned mosaicWidth; + unsigned mosaicHeight; + unsigned mosaicStride; + unsigned mosaicOffset; + vector mosaic; + + unsigned paddingWidth; + unsigned paddingHeight; + unsigned paddingColor; + vector palette; + + inline unsigned objectWidth() const { return blockWidth * tileWidth * mosaicWidth + paddingWidth; } + inline unsigned objectHeight() const { return blockHeight * tileHeight * mosaicHeight + paddingHeight; } + inline unsigned objectSize() const { + unsigned size = blockStride * tileWidth * tileHeight * mosaicWidth * mosaicHeight + + blockOffset * tileHeight * mosaicWidth * mosaicHeight + + tileStride * mosaicWidth * mosaicHeight + + tileOffset * mosaicHeight; + return max(1u, size); + } + + inline unsigned eval(const string &expression) { + intmax_t result; + if(fixedpoint::eval(expression, result) == false) return 0u; + return result; + } + + inline void eval(vector &buffer, const string &expression_) { + string expression = expression_; + bool function = false; + for(auto &c : expression) { + if(c == '(') function = true; + if(c == ')') function = false; + if(c == ',' && function == true) c = ';'; + } + + lstring list = expression.split(","); + for(auto &item : list) { + item.trim(); + if(item.wildcard("f(?*) ?*")) { + item.ltrim<1>("f("); + lstring part = item.split<1>(") "); + lstring args = part[0].split<3>(";"); + for(auto &item : args) item.trim(); + + unsigned length = eval(args(0, "0")); + unsigned offset = eval(args(1, "0")); + unsigned stride = eval(args(2, "0")); + if(args.size() < 2) offset = buffer.size(); + if(args.size() < 3) stride = 1; + + for(unsigned n = 0; n < length; n++) { + string fn = part[1]; + fn.replace("n", decimal(n)); + fn.replace("o", decimal(offset)); + fn.replace("p", decimal(buffer.size())); + buffer.resize(offset + 1); + buffer[offset] = eval(fn); + offset += stride; + } + } else if(item.wildcard("base64*")) { + unsigned offset = 0; + item.ltrim<1>("base64"); + if(item.wildcard("(?*) *")) { + item.ltrim<1>("("); + lstring part = item.split<1>(") "); + offset = eval(part[0]); + item = part(1, ""); + } + item.trim(); + for(auto &c : item) { + if(c >= 'A' && c <= 'Z') buffer.append(offset + c - 'A' + 0); + if(c >= 'a' && c <= 'z') buffer.append(offset + c - 'a' + 26); + if(c >= '0' && c <= '9') buffer.append(offset + c - '0' + 52); + if(c == '-') buffer.append(offset + 62); + if(c == '_') buffer.append(offset + 63); + } + } else if(item.wildcard("file *")) { + item.ltrim<1>("file "); + item.trim(); + //... + } else if(item.empty() == false) { + buffer.append(eval(item)); + } + } + } + + inline void parse(const string &data) { + reset(); + + lstring lines = data.split("\n"); + for(auto &line : lines) { + lstring part = line.split<1>(":"); + if(part.size() != 2) continue; + part[0].trim(); + part[1].trim(); + + if(part[0] == "offset") offset = eval(part[1]); + if(part[0] == "width") width = eval(part[1]); + if(part[0] == "height") height = eval(part[1]); + if(part[0] == "count") count = eval(part[1]); + + if(part[0] == "endian") endian = eval(part[1]); + if(part[0] == "order") order = eval(part[1]); + if(part[0] == "depth") depth = eval(part[1]); + + if(part[0] == "blockWidth") blockWidth = eval(part[1]); + if(part[0] == "blockHeight") blockHeight = eval(part[1]); + if(part[0] == "blockStride") blockStride = eval(part[1]); + if(part[0] == "blockOffset") blockOffset = eval(part[1]); + if(part[0] == "block") eval(block, part[1]); + + if(part[0] == "tileWidth") tileWidth = eval(part[1]); + if(part[0] == "tileHeight") tileHeight = eval(part[1]); + if(part[0] == "tileStride") tileStride = eval(part[1]); + if(part[0] == "tileOffset") tileOffset = eval(part[1]); + if(part[0] == "tile") eval(tile, part[1]); + + if(part[0] == "mosaicWidth") mosaicWidth = eval(part[1]); + if(part[0] == "mosaicHeight") mosaicHeight = eval(part[1]); + if(part[0] == "mosaicStride") mosaicStride = eval(part[1]); + if(part[0] == "mosaicOffset") mosaicOffset = eval(part[1]); + if(part[0] == "mosaic") eval(mosaic, part[1]); + + if(part[0] == "paddingWidth") paddingWidth = eval(part[1]); + if(part[0] == "paddingHeight") paddingHeight = eval(part[1]); + if(part[0] == "paddingColor") paddingColor = eval(part[1]); + if(part[0] == "palette") eval(palette, part[1]); + } + + sanitize(); + } + + inline bool load(const string &filename) { + string filedata; + if(filedata.readfile(filename) == false) return false; + parse(filedata); + return true; + } + + inline void sanitize() { + if(depth < 1) depth = 1; + if(depth > 24) depth = 24; + + if(blockWidth < 1) blockWidth = 1; + if(blockHeight < 1) blockHeight = 1; + + if(tileWidth < 1) tileWidth = 1; + if(tileHeight < 1) tileHeight = 1; + + if(mosaicWidth < 1) mosaicWidth = 1; + if(mosaicHeight < 1) mosaicHeight = 1; + } + + inline void reset() { + offset = 0; + width = 0; + height = 0; + count = 0; + + endian = 1; + order = 0; + depth = 1; + + blockWidth = 1; + blockHeight = 1; + blockStride = 0; + blockOffset = 0; + block.reset(); + + tileWidth = 1; + tileHeight = 1; + tileStride = 0; + tileOffset = 0; + tile.reset(); + + mosaicWidth = 1; + mosaicHeight = 1; + mosaicStride = 0; + mosaicOffset = 0; + mosaic.reset(); + + paddingWidth = 0; + paddingHeight = 0; + paddingColor = 0x000000; + palette.reset(); + } + + inline context() { + reset(); + } +}; + +} +} + +#endif diff --git a/kaijuu/nall/mosaic/parser.hpp b/kaijuu/nall/mosaic/parser.hpp new file mode 100644 index 00000000..b2c0b8ef --- /dev/null +++ b/kaijuu/nall/mosaic/parser.hpp @@ -0,0 +1,126 @@ +#ifdef NALL_MOSAIC_INTERNAL_HPP + +namespace nall { +namespace mosaic { + +struct parser { + image canvas; + + //export from bitstream to canvas + inline void load(bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) { + canvas.allocate(width, height); + canvas.clear(ctx.paddingColor); + parse(1, stream, offset, ctx, width, height); + } + + //import from canvas to bitstream + inline bool save(bitstream &stream, uint64_t offset, context &ctx) { + if(stream.readonly) return false; + parse(0, stream, offset, ctx, canvas.width, canvas.height); + return true; + } + + inline parser() : canvas(0, 32, 0u, 255u << 16, 255u << 8, 255u << 0) { + } + +private: + inline uint32_t read(unsigned x, unsigned y) const { + unsigned addr = y * canvas.width + x; + if(addr >= canvas.width * canvas.height) return 0u; + uint32_t *buffer = (uint32_t*)canvas.data; + return buffer[addr]; + } + + inline void write(unsigned x, unsigned y, uint32_t data) { + unsigned addr = y * canvas.width + x; + if(addr >= canvas.width * canvas.height) return; + uint32_t *buffer = (uint32_t*)canvas.data; + buffer[addr] = data; + } + + inline void parse(bool load, bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) { + stream.endian = ctx.endian; + unsigned canvasWidth = width / (ctx.mosaicWidth * ctx.tileWidth * ctx.blockWidth + ctx.paddingWidth); + unsigned canvasHeight = height / (ctx.mosaicHeight * ctx.tileHeight * ctx.blockHeight + ctx.paddingHeight); + unsigned bitsPerBlock = ctx.depth * ctx.blockWidth * ctx.blockHeight; + + unsigned objectOffset = 0; + for(unsigned objectY = 0; objectY < canvasHeight; objectY++) { + for(unsigned objectX = 0; objectX < canvasWidth; objectX++) { + if(objectOffset >= ctx.count && ctx.count > 0) break; + unsigned objectIX = objectX * ctx.objectWidth(); + unsigned objectIY = objectY * ctx.objectHeight(); + objectOffset++; + + unsigned mosaicOffset = 0; + for(unsigned mosaicY = 0; mosaicY < ctx.mosaicHeight; mosaicY++) { + for(unsigned mosaicX = 0; mosaicX < ctx.mosaicWidth; mosaicX++) { + unsigned mosaicData = ctx.mosaic(mosaicOffset, mosaicOffset); + unsigned mosaicIX = (mosaicData % ctx.mosaicWidth) * (ctx.tileWidth * ctx.blockWidth); + unsigned mosaicIY = (mosaicData / ctx.mosaicWidth) * (ctx.tileHeight * ctx.blockHeight); + mosaicOffset++; + + unsigned tileOffset = 0; + for(unsigned tileY = 0; tileY < ctx.tileHeight; tileY++) { + for(unsigned tileX = 0; tileX < ctx.tileWidth; tileX++) { + unsigned tileData = ctx.tile(tileOffset, tileOffset); + unsigned tileIX = (tileData % ctx.tileWidth) * ctx.blockWidth; + unsigned tileIY = (tileData / ctx.tileWidth) * ctx.blockHeight; + tileOffset++; + + unsigned blockOffset = 0; + for(unsigned blockY = 0; blockY < ctx.blockHeight; blockY++) { + for(unsigned blockX = 0; blockX < ctx.blockWidth; blockX++) { + if(load) { + unsigned palette = 0; + for(unsigned n = 0; n < ctx.depth; n++) { + unsigned index = blockOffset++; + if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth); + palette |= stream.read(offset + ctx.block(index, index)) << n; + } + + write( + objectIX + mosaicIX + tileIX + blockX, + objectIY + mosaicIY + tileIY + blockY, + ctx.palette(palette, palette) + ); + } else /* save */ { + uint32_t palette = read( + objectIX + mosaicIX + tileIX + blockX, + objectIY + mosaicIY + tileIY + blockY + ); + + for(unsigned n = 0; n < ctx.depth; n++) { + unsigned index = blockOffset++; + if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth); + stream.write(offset + ctx.block(index, index), palette & 1); + palette >>= 1; + } + } + } //blockX + } //blockY + + offset += ctx.blockStride; + } //tileX + + offset += ctx.blockOffset; + } //tileY + + offset += ctx.tileStride; + } //mosaicX + + offset += ctx.tileOffset; + } //mosaicY + + offset += ctx.mosaicStride; + } //objectX + + offset += ctx.mosaicOffset; + } //objectY + } +}; + +} +} + +#endif diff --git a/kaijuu/nall/nall.hpp b/kaijuu/nall/nall.hpp new file mode 100644 index 00000000..9a8f1dfa --- /dev/null +++ b/kaijuu/nall/nall.hpp @@ -0,0 +1,56 @@ +#ifndef NALL_HPP +#define NALL_HPP + +//include the most common nall headers with one statement +//does not include the most obscure components with high cost and low usage + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_WINDOWS) + #include + #include +#endif + +#if defined(PLATFORM_X) + #include +#endif + +#endif diff --git a/kaijuu/nall/platform.hpp b/kaijuu/nall/platform.hpp new file mode 100644 index 00000000..a45a6723 --- /dev/null +++ b/kaijuu/nall/platform.hpp @@ -0,0 +1,86 @@ +#ifndef NALL_PLATFORM_HPP +#define NALL_PLATFORM_HPP + +#if defined(_WIN32) + //minimum version needed for _wstat64, etc + #undef __MSVCRT_VERSION__ + #define __MSVCRT_VERSION__ 0x0601 + #include +#endif + +//========================= +//standard platform headers +//========================= + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(_WIN32) + #include + #include + #include + #include + #undef interface + #define dllexport __declspec(dllexport) +#else + #include + #include + #define dllexport +#endif + +//================== +//warning supression +//================== + +//Visual C++ +#if defined(_MSC_VER) + //disable libc "deprecation" warnings + #pragma warning(disable:4996) +#endif + +//================ +//POSIX compliance +//================ + +#if defined(_MSC_VER) + #define PATH_MAX _MAX_PATH + #define va_copy(dest, src) ((dest) = (src)) +#endif + +#if defined(_WIN32) + #define getcwd _getcwd + #define putenv _putenv + #define vsnprintf _vsnprintf + inline void usleep(unsigned milliseconds) { Sleep(milliseconds / 1000); } +#endif + +//================ +//inline expansion +//================ + +#if defined(__GNUC__) + #define noinline __attribute__((noinline)) + #define inline inline + #define alwaysinline inline __attribute__((always_inline)) +#elif defined(_MSC_VER) + #define noinline __declspec(noinline) + #define inline inline + #define alwaysinline inline __forceinline +#else + #define noinline + #define inline inline + #define alwaysinline inline +#endif + +#endif diff --git a/snesfilter/nall/png.hpp b/kaijuu/nall/png.hpp old mode 100755 new mode 100644 similarity index 98% rename from snesfilter/nall/png.hpp rename to kaijuu/nall/png.hpp index 4b474724..f5ebaab4 --- a/snesfilter/nall/png.hpp +++ b/kaijuu/nall/png.hpp @@ -58,12 +58,10 @@ protected: }; bool png::decode(const string &filename) { - uint8_t *data; - unsigned size; - if(file::read(filename, data, size) == false) return false; - bool result = decode(data, size); - delete[] data; - return result; + if(auto memory = file::read(filename)) { + return decode(memory.data(), memory.size()); + } + return false; } bool png::decode(const uint8_t *sourceData, unsigned sourceSize) { diff --git a/snesfilter/nall/priorityqueue.hpp b/kaijuu/nall/priority-queue.hpp old mode 100755 new mode 100644 similarity index 97% rename from snesfilter/nall/priorityqueue.hpp rename to kaijuu/nall/priority-queue.hpp index 443eac21..1aedc6f1 --- a/snesfilter/nall/priorityqueue.hpp +++ b/kaijuu/nall/priority-queue.hpp @@ -1,5 +1,5 @@ -#ifndef NALL_PRIORITYQUEUE_HPP -#define NALL_PRIORITYQUEUE_HPP +#ifndef NALL_PRIORITY_QUEUE_HPP +#define NALL_PRIORITY_QUEUE_HPP #include #include diff --git a/snesfilter/nall/property.hpp b/kaijuu/nall/property.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/property.hpp rename to kaijuu/nall/property.hpp diff --git a/snesfilter/nall/public_cast.hpp b/kaijuu/nall/public-cast.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/public_cast.hpp rename to kaijuu/nall/public-cast.hpp diff --git a/snesfilter/nall/random.hpp b/kaijuu/nall/random.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/random.hpp rename to kaijuu/nall/random.hpp diff --git a/snesfilter/nall/serial.hpp b/kaijuu/nall/serial.hpp old mode 100755 new mode 100644 similarity index 73% rename from snesfilter/nall/serial.hpp rename to kaijuu/nall/serial.hpp index 9ac8451a..da87ae50 --- a/snesfilter/nall/serial.hpp +++ b/kaijuu/nall/serial.hpp @@ -9,14 +9,39 @@ #include namespace nall { - class serial { - public: + struct serial { + bool readable() { + if(port_open == false) return false; + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(port, &fdset); + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + int result = select(FD_SETSIZE, &fdset, nullptr, nullptr, &timeout); + if(result < 1) return false; + return FD_ISSET(port, &fdset); + } + //-1 on error, otherwise return bytes read int read(uint8_t *data, unsigned length) { if(port_open == false) return -1; return ::read(port, (void*)data, length); } + bool writable() { + if(port_open == false) return false; + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(port, &fdset); + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + int result = select(FD_SETSIZE, nullptr, &fdset, nullptr, &timeout); + if(result < 1) return false; + return FD_ISSET(port, &fdset); + } + //-1 on error, otherwise return bytes written int write(const uint8_t *data, unsigned length) { if(port_open == false) return -1; diff --git a/snesfilter/nall/serializer.hpp b/kaijuu/nall/serializer.hpp old mode 100755 new mode 100644 similarity index 94% rename from snesfilter/nall/serializer.hpp rename to kaijuu/nall/serializer.hpp index ff2337ab..fcb39456 --- a/snesfilter/nall/serializer.hpp +++ b/kaijuu/nall/serializer.hpp @@ -55,10 +55,10 @@ namespace nall { template void integer(T &value) { enum { size = std::is_same::value ? 1 : sizeof(T) }; if(imode == Save) { - for(unsigned n = 0; n < size; n++) idata[isize++] = value >> (n << 3); + for(unsigned n = 0; n < size; n++) idata[isize++] = (uintmax_t)value >> (n << 3); } else if(imode == Load) { value = 0; - for(unsigned n = 0; n < size; n++) value |= idata[isize++] << (n << 3); + for(unsigned n = 0; n < size; n++) value |= (uintmax_t)idata[isize++] << (n << 3); } else if(imode == Size) { isize += size; } diff --git a/kaijuu/nall/set.hpp b/kaijuu/nall/set.hpp new file mode 100644 index 00000000..c6d3d06e --- /dev/null +++ b/kaijuu/nall/set.hpp @@ -0,0 +1,158 @@ +#ifndef NALL_SET_HPP +#define NALL_SET_HPP + +//set +//* unordered +//* intended for unique items +//* dynamic growth +//* reference-based variant + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nall { + +template struct set; + +template struct set::value>::type> { + struct exception_out_of_bounds{}; + +protected: + T *pool; + unsigned poolsize, objectsize; + +public: + unsigned size() const { return objectsize; } + unsigned capacity() const { return poolsize; } +}; + +//reference set +template struct set::value>::type> { + struct exception_out_of_bounds{}; + +protected: + typedef typename std::remove_reference::type T; + T **pool; + unsigned poolsize, objectsize; + +public: + unsigned size() const { return objectsize; } + unsigned capacity() const { return poolsize; } + + void reset() { + if(pool) free(pool); + pool = nullptr; + poolsize = 0; + objectsize = 0; + } + + void reserve(unsigned size) { + if(size == poolsize) return; + pool = (T**)realloc(pool, sizeof(T*) * size); + poolsize = size; + objectsize = min(objectsize, size); + } + + void resize(unsigned size) { + if(size > poolsize) reserve(bit::round(size)); //amortize growth + objectsize = size; + } + + bool append(T& data) { + if(find(data)) return false; + unsigned offset = objectsize++; + if(offset >= poolsize) resize(offset + 1); + pool[offset] = &data; + return true; + } + + template + bool append(T& data, Args&&... args) { + bool result = append(data); + append(std::forward(args)...); + return result; + } + + bool remove(T& data) { + if(auto position = find(data)) { + for(signed i = position(); i < objectsize - 1; i++) pool[i] = pool[i + 1]; + resize(objectsize - 1); + return true; + } + return false; + } + + optional find(const T& data) { + for(unsigned n = 0; n < objectsize; n++) if(pool[n] == &data) return {true, n}; + return {false, 0u}; + } + + template set(Args&&... args) : pool(nullptr), poolsize(0), objectsize(0) { + construct(std::forward(args)...); + } + + ~set() { + reset(); + } + + set& operator=(const set &source) { + if(&source == this) return *this; + if(pool) free(pool); + objectsize = source.objectsize; + poolsize = source.poolsize; + pool = (T**)malloc(sizeof(T*) * poolsize); + memcpy(pool, source.pool, sizeof(T*) * objectsize); + return *this; + } + + set& operator=(const set &&source) { + if(&source == this) return *this; + if(pool) free(pool); + pool = source.pool; + poolsize = source.poolsize; + objectsize = source.objectsize; + source.pool = nullptr; + source.reset(); + return *this; + } + + T& operator[](unsigned position) const { + if(position >= objectsize) throw exception_out_of_bounds(); + return *pool[position]; + } + + struct iterator { + bool operator!=(const iterator &source) const { return position != source.position; } + T& operator*() { return source.operator[](position); } + iterator& operator++() { position++; return *this; } + iterator(const set &source, unsigned position) : source(source), position(position) {} + private: + const set &source; + unsigned position; + }; + + iterator begin() { return iterator(*this, 0); } + iterator end() { return iterator(*this, objectsize); } + const iterator begin() const { return iterator(*this, 0); } + const iterator end() const { return iterator(*this, objectsize); } + +private: + void construct() {} + void construct(const set &source) { operator=(source); } + void construct(const set &&source) { operator=(std::move(source)); } + template void construct(T& data, Args&&... args) { + append(data); + construct(std::forward(args)...); + } +}; + +} + +#endif diff --git a/snesfilter/nall/sha256.hpp b/kaijuu/nall/sha256.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/sha256.hpp rename to kaijuu/nall/sha256.hpp diff --git a/kaijuu/nall/sort.hpp b/kaijuu/nall/sort.hpp new file mode 100644 index 00000000..36d91865 --- /dev/null +++ b/kaijuu/nall/sort.hpp @@ -0,0 +1,77 @@ +#ifndef NALL_SORT_HPP +#define NALL_SORT_HPP + +#include +#include + +//class: merge sort +//average: O(n log n) +//worst: O(n log n) +//memory: O(n) +//stack: O(log n) +//stable?: yes + +//note: merge sort was chosen over quick sort, because: +//* it is a stable sort +//* it lacks O(n^2) worst-case overhead + +#define NALL_SORT_INSERTION +//#define NALL_SORT_SELECTION + +namespace nall { + template + void sort(T list[], unsigned size, const Comparator &lessthan) { + if(size <= 1) return; //nothing to sort + + //use insertion sort to quickly sort smaller blocks + if(size < 64) { + #if defined(NALL_SORT_INSERTION) + for(signed i = 1, j; i < size; i++) { + T copy = std::move(list[i]); + for(j = i - 1; j >= 0; j--) { + if(lessthan(list[j], copy)) break; + list[j + 1] = std::move(list[j]); + } + list[j + 1] = std::move(copy); + } + #elif defined(NALL_SORT_SELECTION) + for(unsigned i = 0; i < size; i++) { + unsigned min = i; + for(unsigned j = i + 1; j < size; j++) { + if(lessthan(list[j], list[min])) min = j; + } + if(min != i) std::swap(list[i], list[min]); + } + #endif + return; + } + + //split list in half and recursively sort both + unsigned middle = size / 2; + sort(list, middle, lessthan); + sort(list + middle, size - middle, lessthan); + + //left and right are sorted here; perform merge sort + T *buffer = new T[size]; + unsigned offset = 0, left = 0, right = middle; + while(left < middle && right < size) { + if(lessthan(list[left], list[right])) { + buffer[offset++] = std::move(list[left++]); + } else { + buffer[offset++] = std::move(list[right++]); + } + } + while(left < middle) buffer[offset++] = std::move(list[left++]); + while(right < size) buffer[offset++] = std::move(list[right++]); + + for(unsigned i = 0; i < size; i++) list[i] = std::move(buffer[i]); + delete[] buffer; + } + + template + void sort(T list[], unsigned size) { + return sort(list, size, [](const T &l, const T &r) { return l < r; }); + } +} + +#endif diff --git a/snesfilter/nall/stdint.hpp b/kaijuu/nall/stdint.hpp old mode 100755 new mode 100644 similarity index 97% rename from snesfilter/nall/stdint.hpp rename to kaijuu/nall/stdint.hpp index d8b6c788..c63f5912 --- a/snesfilter/nall/stdint.hpp +++ b/kaijuu/nall/stdint.hpp @@ -1,8 +1,6 @@ #ifndef NALL_STDINT_HPP #define NALL_STDINT_HPP -#include - #if defined(_MSC_VER) typedef signed char int8_t; typedef signed short int16_t; diff --git a/kaijuu/nall/stream.hpp b/kaijuu/nall/stream.hpp new file mode 100644 index 00000000..586ccda7 --- /dev/null +++ b/kaijuu/nall/stream.hpp @@ -0,0 +1,26 @@ +#ifndef NALL_STREAM_HPP +#define NALL_STREAM_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NALL_STREAM_INTERNAL_HPP +#include +#include +#include +#include +#include +#include +#include +#include +#undef NALL_STREAM_INTERNAL_HPP + +#endif diff --git a/kaijuu/nall/stream/auto.hpp b/kaijuu/nall/stream/auto.hpp new file mode 100644 index 00000000..d1b6e2ba --- /dev/null +++ b/kaijuu/nall/stream/auto.hpp @@ -0,0 +1,25 @@ +#ifndef NALL_STREAM_AUTO_HPP +#define NALL_STREAM_AUTO_HPP + +namespace nall { + +#define autostream(...) (*makestream(__VA_ARGS__)) + +inline std::unique_ptr makestream(const string &path) { + if(path.ibeginswith("http://")) return std::unique_ptr(new httpstream(path, 80)); + if(path.iendswith(".gz")) return std::unique_ptr(new gzipstream(filestream{path})); + if(path.iendswith(".zip")) return std::unique_ptr(new zipstream(filestream{path})); + return std::unique_ptr(new mmapstream(path)); +} + +inline std::unique_ptr makestream(uint8_t *data, unsigned size) { + return std::unique_ptr(new memorystream(data, size)); +} + +inline std::unique_ptr makestream(const uint8_t *data, unsigned size) { + return std::unique_ptr(new memorystream(data, size)); +} + +} + +#endif diff --git a/kaijuu/nall/stream/file.hpp b/kaijuu/nall/stream/file.hpp new file mode 100644 index 00000000..878418cf --- /dev/null +++ b/kaijuu/nall/stream/file.hpp @@ -0,0 +1,42 @@ +#ifndef NALL_STREAM_FILE_HPP +#define NALL_STREAM_FILE_HPP + +#include + +namespace nall { + +struct filestream : stream { + using stream::read; + using stream::write; + + bool seekable() const { return true; } + bool readable() const { return true; } + bool writable() const { return pwritable; } + bool randomaccess() const { return false; } + + unsigned size() const { return pfile.size(); } + unsigned offset() const { return pfile.offset(); } + void seek(unsigned offset) const { pfile.seek(offset); } + + uint8_t read() const { return pfile.read(); } + void write(uint8_t data) const { pfile.write(data); } + + filestream(const string &filename) { + pfile.open(filename, file::mode::readwrite); + pwritable = pfile.open(); + if(!pwritable) pfile.open(filename, file::mode::read); + } + + filestream(const string &filename, file::mode mode) { + pfile.open(filename, mode); + pwritable = mode == file::mode::write || mode == file::mode::readwrite; + } + +private: + mutable file pfile; + bool pwritable; +}; + +} + +#endif diff --git a/kaijuu/nall/stream/gzip.hpp b/kaijuu/nall/stream/gzip.hpp new file mode 100644 index 00000000..0c270a72 --- /dev/null +++ b/kaijuu/nall/stream/gzip.hpp @@ -0,0 +1,34 @@ +#ifndef NALL_STREAM_GZIP_HPP +#define NALL_STREAM_GZIP_HPP + +#include + +namespace nall { + +struct gzipstream : memorystream { + using stream::read; + using stream::write; + + gzipstream(const stream &stream) { + unsigned size = stream.size(); + uint8_t *data = new uint8_t[size]; + stream.read(data, size); + + gzip archive; + bool result = archive.decompress(data, size); + delete[] data; + if(result == false) return; + + psize = archive.size; + pdata = new uint8_t[psize]; + memcpy(pdata, archive.data, psize); + } + + ~gzipstream() { + if(pdata) delete[] pdata; + } +}; + +} + +#endif diff --git a/kaijuu/nall/stream/http.hpp b/kaijuu/nall/stream/http.hpp new file mode 100644 index 00000000..2f9e45dd --- /dev/null +++ b/kaijuu/nall/stream/http.hpp @@ -0,0 +1,49 @@ +#ifndef NALL_STREAM_HTTP_HPP +#define NALL_STREAM_HTTP_HPP + +#include + +namespace nall { + +struct httpstream : stream { + using stream::read; + using stream::write; + + bool seekable() const { return true; } + bool readable() const { return true; } + bool writable() const { return true; } + bool randomaccess() const { return true; } + + unsigned size() const { return psize; } + unsigned offset() const { return poffset; } + void seek(unsigned offset) const { poffset = offset; } + + uint8_t read() const { return pdata[poffset++]; } + void write(uint8_t data) const { pdata[poffset++] = data; } + + uint8_t read(unsigned offset) const { return pdata[offset]; } + void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } + + httpstream(const string &url, unsigned port) : pdata(nullptr), psize(0), poffset(0) { + string uri = url; + uri.ltrim<1>("http://"); + lstring part = uri.split<1>("/"); + part[1] = { "/", part[1] }; + + http connection; + if(connection.connect(part[0], port) == false) return; + connection.download(part[1], pdata, psize); + } + + ~httpstream() { + if(pdata) delete[] pdata; + } + +private: + mutable uint8_t *pdata; + mutable unsigned psize, poffset; +}; + +} + +#endif diff --git a/kaijuu/nall/stream/memory.hpp b/kaijuu/nall/stream/memory.hpp new file mode 100644 index 00000000..cf49b3b2 --- /dev/null +++ b/kaijuu/nall/stream/memory.hpp @@ -0,0 +1,47 @@ +#ifndef NALL_STREAM_MEMORY_HPP +#define NALL_STREAM_MEMORY_HPP + +#include + +namespace nall { + +struct memorystream : stream { + using stream::read; + using stream::write; + + bool seekable() const { return true; } + bool readable() const { return true; } + bool writable() const { return pwritable; } + bool randomaccess() const { return true; } + + uint8_t *data() const { return pdata; } + unsigned size() const { return psize; } + unsigned offset() const { return poffset; } + void seek(unsigned offset) const { poffset = offset; } + + uint8_t read() const { return pdata[poffset++]; } + void write(uint8_t data) const { pdata[poffset++] = data; } + + uint8_t read(unsigned offset) const { return pdata[offset]; } + void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } + + memorystream() : pdata(nullptr), psize(0), poffset(0), pwritable(true) {} + + memorystream(uint8_t *data, unsigned size) { + pdata = data, psize = size, poffset = 0; + pwritable = true; + } + + memorystream(const uint8_t *data, unsigned size) { + pdata = (uint8_t*)data, psize = size, poffset = 0; + pwritable = false; + } + +protected: + mutable uint8_t *pdata; + mutable unsigned psize, poffset, pwritable; +}; + +} + +#endif diff --git a/kaijuu/nall/stream/mmap.hpp b/kaijuu/nall/stream/mmap.hpp new file mode 100644 index 00000000..ce30f810 --- /dev/null +++ b/kaijuu/nall/stream/mmap.hpp @@ -0,0 +1,42 @@ +#ifndef NALL_STREAM_MMAP_HPP +#define NALL_STREAM_MMAP_HPP + +#include + +namespace nall { + +struct mmapstream : stream { + using stream::read; + using stream::write; + + bool seekable() const { return true; } + bool readable() const { return true; } + bool writable() const { return pwritable; } + bool randomaccess() const { return true; } + + unsigned size() const { return pmmap.size(); } + unsigned offset() const { return poffset; } + void seek(unsigned offset) const { poffset = offset; } + + uint8_t read() const { return pdata[poffset++]; } + void write(uint8_t data) const { pdata[poffset++] = data; } + + uint8_t read(unsigned offset) const { return pdata[offset]; } + void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } + + mmapstream(const string &filename) { + pmmap.open(filename, filemap::mode::readwrite); + pwritable = pmmap.open(); + if(!pwritable) pmmap.open(filename, filemap::mode::read); + pdata = pmmap.data(), poffset = 0; + } + +private: + mutable filemap pmmap; + mutable uint8_t *pdata; + mutable unsigned pwritable, poffset; +}; + +} + +#endif diff --git a/kaijuu/nall/stream/stream.hpp b/kaijuu/nall/stream/stream.hpp new file mode 100644 index 00000000..9d937729 --- /dev/null +++ b/kaijuu/nall/stream/stream.hpp @@ -0,0 +1,92 @@ +#ifndef NALL_STREAM_STREAM_HPP +#define NALL_STREAM_STREAM_HPP + +namespace nall { + +struct stream { + virtual bool seekable() const = 0; + virtual bool readable() const = 0; + virtual bool writable() const = 0; + virtual bool randomaccess() const = 0; + + virtual uint8_t* data() const { return nullptr; } + virtual unsigned size() const = 0; + virtual unsigned offset() const = 0; + virtual void seek(unsigned offset) const = 0; + + virtual uint8_t read() const = 0; + virtual void write(uint8_t data) const = 0; + + virtual uint8_t read(unsigned) const { return 0; } + virtual void write(unsigned, uint8_t) const {} + + operator bool() const { + return size(); + } + + bool empty() const { + return size() == 0; + } + + bool end() const { + return offset() >= size(); + } + + uintmax_t readl(unsigned length = 1) const { + uintmax_t data = 0, shift = 0; + while(length--) { data |= read() << shift; shift += 8; } + return data; + } + + uintmax_t readm(unsigned length = 1) const { + uintmax_t data = 0; + while(length--) data = (data << 8) | read(); + return data; + } + + void read(uint8_t *data, unsigned length) const { + while(length--) *data++ = read(); + } + + void writel(uintmax_t data, unsigned length = 1) const { + while(length--) { + write(data); + data >>= 8; + } + } + + void writem(uintmax_t data, unsigned length = 1) const { + uintmax_t shift = 8 * length; + while(length--) { + shift -= 8; + write(data >> shift); + } + } + + void write(const uint8_t *data, unsigned length) const { + while(length--) write(*data++); + } + + struct byte { + operator uint8_t() const { return s.read(offset); } + byte& operator=(uint8_t data) { s.write(offset, data); return *this; } + byte(const stream &s, unsigned offset) : s(s), offset(offset) {} + + private: + const stream &s; + const unsigned offset; + }; + + byte operator[](unsigned offset) const { + return byte(*this, offset); + } + + stream() {} + virtual ~stream() {} + stream(const stream&) = delete; + stream& operator=(const stream&) = delete; +}; + +} + +#endif diff --git a/kaijuu/nall/stream/vector.hpp b/kaijuu/nall/stream/vector.hpp new file mode 100644 index 00000000..59f36c02 --- /dev/null +++ b/kaijuu/nall/stream/vector.hpp @@ -0,0 +1,39 @@ +#ifndef NALL_STREAM_VECTOR_HPP +#define NALL_STREAM_VECTOR_HPP + +#include +#include + +namespace nall { + +struct vectorstream : stream { + using stream::read; + using stream::write; + + bool seekable() const { return true; } + bool readable() const { return true; } + bool writable() const { return pwritable; } + bool randomaccess() const { return true; } + + uint8_t* data() const { return memory.data(); } + unsigned size() const { return memory.size(); } + unsigned offset() const { return poffset; } + void seek(unsigned offset) const { poffset = offset; } + + uint8_t read() const { return memory[poffset++]; } + void write(uint8_t data) const { memory[poffset++] = data; } + + uint8_t read(unsigned offset) const { return memory[offset]; } + void write(unsigned offset, uint8_t data) const { memory[offset] = data; } + + vectorstream(vector &memory) : memory(memory), poffset(0), pwritable(true) {} + vectorstream(const vector &memory) : memory((vector&)memory), poffset(0), pwritable(false) {} + +protected: + vector &memory; + mutable unsigned poffset, pwritable; +}; + +} + +#endif diff --git a/kaijuu/nall/stream/zip.hpp b/kaijuu/nall/stream/zip.hpp new file mode 100644 index 00000000..975cdeff --- /dev/null +++ b/kaijuu/nall/stream/zip.hpp @@ -0,0 +1,38 @@ +#ifndef NALL_STREAM_ZIP_HPP +#define NALL_STREAM_ZIP_HPP + +#include + +namespace nall { + +struct zipstream : memorystream { + using stream::read; + using stream::write; + + zipstream(const stream &stream, const string &filter = "*") { + unsigned size = stream.size(); + uint8_t *data = new uint8_t[size]; + stream.read(data, size); + + zip archive; + if(archive.open(data, size) == false) return; + delete[] data; + + for(auto &file : archive.file) { + if(file.name.wildcard(filter)) { + auto buffer = archive.extract(file); + psize = buffer.size(); + pdata = buffer.move(); + return; + } + } + } + + ~zipstream() { + if(pdata) delete[] pdata; + } +}; + +} + +#endif diff --git a/snesfilter/nall/string.hpp b/kaijuu/nall/string.hpp old mode 100755 new mode 100644 similarity index 92% rename from snesfilter/nall/string.hpp rename to kaijuu/nall/string.hpp index 288424bc..8c4f6b2c --- a/snesfilter/nall/string.hpp +++ b/kaijuu/nall/string.hpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -25,21 +24,22 @@ #include #include #include -#include #include #include #include +#include #include #include -#include #include #include #include -#include +#include #include #include #include #include +#include +#include #include #include #include diff --git a/snesfilter/nall/string/base.hpp b/kaijuu/nall/string/base.hpp old mode 100755 new mode 100644 similarity index 87% rename from snesfilter/nall/string/base.hpp rename to kaijuu/nall/string/base.hpp index 97000bef..f70c1247 --- a/snesfilter/nall/string/base.hpp +++ b/kaijuu/nall/string/base.hpp @@ -22,7 +22,10 @@ namespace nall { }; struct string { + inline static string read(const string &filename); + inline void reserve(unsigned); + inline bool empty() const; template inline string& assign(Args&&... args); template inline string& append(Args&&... args); @@ -35,6 +38,7 @@ namespace nall { template inline string& iqreplace(const char*, const char*); inline unsigned length() const; + inline unsigned capacity() const; template inline lstring split(const char*) const; template inline lstring isplit(const char*) const; @@ -109,6 +113,10 @@ namespace nall { struct lstring : vector { inline optional find(const char*) const; + inline string concatenate(const char*) const; + inline void append() {} + template inline void append(const string&, Args&&...); + template inline lstring& split(const char*, const char*); template inline lstring& isplit(const char*, const char*); template inline lstring& qsplit(const char*, const char*); @@ -117,8 +125,14 @@ namespace nall { inline bool operator==(const lstring&) const; inline bool operator!=(const lstring&) const; - inline lstring(); - inline lstring(std::initializer_list); + inline lstring& operator=(const lstring&); + inline lstring& operator=(lstring&); + inline lstring& operator=(lstring&&); + + template inline lstring(Args&&... args); + inline lstring(const lstring&); + inline lstring(lstring&); + inline lstring(lstring&&); protected: template inline lstring& usplit(const char*, const char*); @@ -145,13 +159,17 @@ namespace nall { inline bool strmath(const char *str, int &result); //platform.hpp - inline string realpath(const char *name); + inline string activepath(); + inline string realpath(const string &name); inline string userpath(); - inline string currentpath(); + inline string configpath(); - //strl.hpp - inline unsigned strlcpy(char *dest, const char *src, unsigned length); - inline unsigned strlcat(char *dest, const char *src, unsigned length); + //strm.hpp + inline unsigned strmcpy(char *target, const char *source, unsigned length); + inline unsigned strmcat(char *target, const char *source, unsigned length); + inline bool strccpy(char *target, const char *source, unsigned length); + inline bool strccat(char *target, const char *source, unsigned length); + inline void strpcpy(char *&target, const char *source, unsigned &length); //strpos.hpp inline optional strpos(const char *str, const char *key); @@ -169,8 +187,6 @@ namespace nall { template alwaysinline bool chrequal(char x, char y); template alwaysinline bool quoteskip(T *&p); template alwaysinline bool quotecopy(char *&t, T *&p); - inline unsigned strlcpy(string &dest, const char *src, unsigned length); - inline unsigned strlcat(string &dest, const char *src, unsigned length); inline string substr(const char *src, unsigned start = 0, unsigned length = ~0u); inline string sha256(const uint8_t *data, unsigned size); diff --git a/snesfilter/nall/string/bml.hpp b/kaijuu/nall/string/bml.hpp old mode 100755 new mode 100644 similarity index 97% rename from snesfilter/nall/string/bml.hpp rename to kaijuu/nall/string/bml.hpp index 4f8139cc..de1f07a0 --- a/snesfilter/nall/string/bml.hpp +++ b/kaijuu/nall/string/bml.hpp @@ -7,12 +7,12 @@ namespace nall { namespace BML { inline static string indent(const char *s, unsigned depth) { - array output; + vector output; do { for(unsigned n = 0; n < depth; n++) output.append('\t'); do output.append(*s); while(*s && *s++ != '\n'); } while(*s); - return output.get(); + return output.data(); } struct Node { @@ -20,7 +20,7 @@ struct Node { cstring value; private: - linear_vector children; + vector children; inline bool valid(char p) const { //A-Za-z0-9-. return p - 'A' < 26u | p - 'a' < 26u | p - '0' < 10u | p - '-' < 2u; diff --git a/snesfilter/nall/string/bsv.hpp b/kaijuu/nall/string/bsv.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/bsv.hpp rename to kaijuu/nall/string/bsv.hpp diff --git a/snesfilter/nall/string/cast.hpp b/kaijuu/nall/string/cast.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/cast.hpp rename to kaijuu/nall/string/cast.hpp diff --git a/snesfilter/nall/string/compare.hpp b/kaijuu/nall/string/compare.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/compare.hpp rename to kaijuu/nall/string/compare.hpp diff --git a/snesfilter/nall/string/convert.hpp b/kaijuu/nall/string/convert.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/convert.hpp rename to kaijuu/nall/string/convert.hpp diff --git a/snesfilter/nall/string/core.hpp b/kaijuu/nall/string/core.hpp old mode 100755 new mode 100644 similarity index 76% rename from snesfilter/nall/string/core.hpp rename to kaijuu/nall/string/core.hpp index 5ae2bd48..d5f75f3a --- a/snesfilter/nall/string/core.hpp +++ b/kaijuu/nall/string/core.hpp @@ -19,6 +19,10 @@ void string::reserve(unsigned size_) { } } +bool string::empty() const { + return !*data; +} + template string& string::assign(Args&&... args) { *data = 0; istring(*this, std::forward(args)...); @@ -134,6 +138,19 @@ optional lstring::find(const char *key) const { return { false, 0 }; } +string lstring::concatenate(const char *separator) const { + string output; + for(unsigned i = 0; i < size(); i++) { + output.append(operator[](i), i < size() - 1 ? separator : ""); + } + return output; +} + +template void lstring::append(const string &data, Args&&... args) { + vector::append(data); + append(std::forward(args)...); +} + bool lstring::operator==(const lstring &source) const { if(this == &source) return true; if(size() != source.size()) return false; @@ -147,11 +164,35 @@ bool lstring::operator!=(const lstring &source) const { return !operator==(source); } -inline lstring::lstring() { +lstring& lstring::operator=(const lstring &source) { + vector::operator=(source); + return *this; } -inline lstring::lstring(std::initializer_list list) { - for(auto &data : list) append(data); +lstring& lstring::operator=(lstring &source) { + vector::operator=(source); + return *this; +} + +lstring& lstring::operator=(lstring &&source) { + vector::operator=(std::move(source)); + return *this; +} + +template lstring::lstring(Args&&... args) { + append(std::forward(args)...); +} + +lstring::lstring(const lstring &source) { + vector::operator=(source); +} + +lstring::lstring(lstring &source) { + vector::operator=(source); +} + +lstring::lstring(lstring &&source) { + vector::operator=(std::move(source)); } } diff --git a/snesfilter/nall/string/cstring.hpp b/kaijuu/nall/string/cstring.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/cstring.hpp rename to kaijuu/nall/string/cstring.hpp diff --git a/kaijuu/nall/string/filename.hpp b/kaijuu/nall/string/filename.hpp new file mode 100644 index 00000000..19b5f117 --- /dev/null +++ b/kaijuu/nall/string/filename.hpp @@ -0,0 +1,74 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +// "/foo/bar.c" -> "/foo/" +// "/foo/" -> "/foo/" +// "bar.c" -> "./" +inline string dir(string name) { + for(signed i = name.length(); i >= 0; i--) { + if(name[i] == '/' || name[i] == '\\') { + name[i + 1] = 0; + break; + } + if(i == 0) name = "./"; + } + return name; +} + +// "/foo/bar.c" -> "bar.c" +// "/foo/" -> "" +// "bar.c" -> "bar.c" +inline string notdir(string name) { + for(signed i = name.length(); i >= 0; i--) { + if(name[i] == '/' || name[i] == '\\') { + return (const char*)name + i + 1; + } + } + return name; +} + +// "/foo/bar/baz" -> "/foo/bar/" +// "/foo/bar/" -> "/foo/" +// "/foo/bar" -> "/foo/" +inline string parentdir(string name) { + unsigned length = name.length(), paths = 0, prev, last; + for(unsigned i = 0; i < length; i++) { + if(name[i] == '/' || name[i] == '\\') { + paths++; + prev = last; + last = i; + } + } + if(last + 1 == length) last = prev; //if name ends in slash; use previous slash + if(paths > 1) name[last + 1] = 0; + return name; +} + +// "/foo/bar.c" -> "/foo/bar" +inline string basename(string name) { + for(signed i = name.length(); i >= 0; i--) { + if(name[i] == '/' || name[i] == '\\') break; //file has no extension + if(name[i] == '.') { + name[i] = 0; + break; + } + } + return name; +} + +// "/foo/bar.c" -> "c" +// "/foo/bar" -> "" +inline string extension(string name) { + for(signed i = name.length(); i >= 0; i--) { + if(name[i] == '/' || name[i] == '\\') return ""; //file has no extension + if(name[i] == '.') { + return (const char*)name + i + 1; + } + } + return name; +} + +} + +#endif diff --git a/snesfilter/nall/string/math-fixed-point.hpp b/kaijuu/nall/string/math-fixed-point.hpp old mode 100755 new mode 100644 similarity index 96% rename from snesfilter/nall/string/math-fixed-point.hpp rename to kaijuu/nall/string/math-fixed-point.hpp index 744621d1..a61b23f3 --- a/snesfilter/nall/string/math-fixed-point.hpp +++ b/kaijuu/nall/string/math-fixed-point.hpp @@ -152,6 +152,15 @@ static bool eval(const char *s, intmax_t &result) { } } +static intmax_t parse(const char *s) { + try { + intmax_t result = eval(s); + return result; + } catch(const char *) { + return 0; + } +} + } #endif diff --git a/snesfilter/nall/string/math-floating-point.hpp b/kaijuu/nall/string/math-floating-point.hpp old mode 100755 new mode 100644 similarity index 96% rename from snesfilter/nall/string/math-floating-point.hpp rename to kaijuu/nall/string/math-floating-point.hpp index 85680aad..43a2f0f4 --- a/snesfilter/nall/string/math-floating-point.hpp +++ b/kaijuu/nall/string/math-floating-point.hpp @@ -138,12 +138,20 @@ static bool eval(const char *s, double &result) { result = eval(s); return true; } catch(const char*e) { -printf("%s\n", e); result = 0; return false; } } +static double parse(const char *s) { + try { + double result = eval(s); + return result; + } catch(const char *) { + return 0; + } +} + } #endif diff --git a/kaijuu/nall/string/platform.hpp b/kaijuu/nall/string/platform.hpp new file mode 100644 index 00000000..469d79b3 --- /dev/null +++ b/kaijuu/nall/string/platform.hpp @@ -0,0 +1,63 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +string activepath() { + string result; + #ifdef _WIN32 + wchar_t path[PATH_MAX] = L""; + _wgetcwd(path, PATH_MAX); + result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #else + char path[PATH_MAX] = ""; + getcwd(path, PATH_MAX); + result = path; + #endif + if(result.empty()) result = "."; + if(result.endswith("/") == false) result.append("/"); + return result; +} + +string realpath(const string &name) { + string result; + #ifdef _WIN32 + wchar_t path[PATH_MAX] = L""; + if(_wfullpath(path, utf16_t(name), PATH_MAX)) result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #else + char path[PATH_MAX] = ""; + if(::realpath(name, path)) result = path; + #endif + return result; +} + +string userpath() { + string result; + #ifdef _WIN32 + wchar_t path[PATH_MAX] = L""; + SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, path); + result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #else + char path[PATH_MAX] = ""; + struct passwd *userinfo = getpwuid(getuid()); + if(userinfo) strcpy(path, userinfo->pw_dir); + result = path; + #endif + if(result.empty()) result = "."; + if(result.endswith("/") == false) result.append("/"); + return result; +} + +string configpath() { + #ifdef _WIN32 + return userpath(); + #else + return {userpath(), ".config/"}; + #endif +} + +} + +#endif diff --git a/snesfilter/nall/string/replace.hpp b/kaijuu/nall/string/replace.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/replace.hpp rename to kaijuu/nall/string/replace.hpp diff --git a/snesfilter/nall/string/split.hpp b/kaijuu/nall/string/split.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/split.hpp rename to kaijuu/nall/string/split.hpp diff --git a/kaijuu/nall/string/static.hpp b/kaijuu/nall/string/static.hpp new file mode 100644 index 00000000..ca521cb0 --- /dev/null +++ b/kaijuu/nall/string/static.hpp @@ -0,0 +1,13 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +string string::read(const string &filename) { + string data; + data.readfile(filename); + return data; +} + +} + +#endif diff --git a/kaijuu/nall/string/strm.hpp b/kaijuu/nall/string/strm.hpp new file mode 100644 index 00000000..21d05652 --- /dev/null +++ b/kaijuu/nall/string/strm.hpp @@ -0,0 +1,45 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +// +//strmcpy, strmcat created by byuu +// + +//return = strlen(target) +unsigned strmcpy(char *target, const char *source, unsigned length) { + const char *origin = target; + if(length) { + while(*source && --length) *target++ = *source++; + *target = 0; + } + return target - origin; +} + +//return = strlen(target) +unsigned strmcat(char *target, const char *source, unsigned length) { + const char *origin = target; + while(*target && length) target++, length--; + return (target - origin) + strmcpy(target, source, length); +} + +//return = true when all of source was copied +bool strccpy(char *target, const char *source, unsigned length) { + return !source[strmcpy(target, source, length)]; +} + +//return = true when all of source was copied +bool strccat(char *target, const char *source, unsigned length) { + while(*target && length) target++, length--; + return !source[strmcpy(target, source, length)]; +} + +//return = reserved for future use +void strpcpy(char *&target, const char *source, unsigned &length) { + unsigned offset = strmcpy(target, source, length); + target += offset, length -= offset; +} + +} + +#endif diff --git a/snesfilter/nall/string/strpos.hpp b/kaijuu/nall/string/strpos.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/strpos.hpp rename to kaijuu/nall/string/strpos.hpp diff --git a/snesfilter/nall/string/trim.hpp b/kaijuu/nall/string/trim.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/trim.hpp rename to kaijuu/nall/string/trim.hpp diff --git a/kaijuu/nall/string/utf8.hpp b/kaijuu/nall/string/utf8.hpp new file mode 100644 index 00000000..77397bf2 --- /dev/null +++ b/kaijuu/nall/string/utf8.hpp @@ -0,0 +1,43 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +struct UTF8 { + unsigned size; //size of encoded codepoint + uint64_t data; //encoded codepoint + unsigned codepoint; //decoded codepoint +}; + +inline UTF8 utf8_read(const char *s) { + UTF8 utf8; + + if((*s & 0xfe) == 0xfc) utf8.size = 6; + else if((*s & 0xfc) == 0xf8) utf8.size = 5; + else if((*s & 0xf8) == 0xf0) utf8.size = 4; + else if((*s & 0xf0) == 0xe0) utf8.size = 3; + else if((*s & 0xe0) == 0xc0) utf8.size = 2; + else utf8.size = 1; + + utf8.data = 0; + for(unsigned n = 0; n < utf8.size; n++) { + utf8.data = (utf8.data << 8) | (uint8_t)s[n]; + } + + static uint8_t mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; + utf8.codepoint = s[0] & mask[utf8.size]; + for(unsigned n = 1; n < utf8.size; n++) { + utf8.codepoint = (utf8.codepoint << 6) | (s[n] & 0x3f); + } + + return utf8; +} + +inline void utf8_write(char *s, const UTF8 &utf8) { + for(signed n = utf8.size - 1, shift = 0; n >= 0; n--, shift += 8) { + s[n] = utf8.data >> shift; + } +} + +} + +#endif diff --git a/snesfilter/nall/string/utility.hpp b/kaijuu/nall/string/utility.hpp old mode 100755 new mode 100644 similarity index 94% rename from snesfilter/nall/string/utility.hpp rename to kaijuu/nall/string/utility.hpp index 2212688b..b2f93d2c --- a/snesfilter/nall/string/utility.hpp +++ b/kaijuu/nall/string/utility.hpp @@ -34,24 +34,16 @@ bool quotecopy(char *&t, T *&p) { return true; } -unsigned strlcpy(string &dest, const char *src, unsigned length) { - dest.reserve(length); - return strlcpy(dest(), src, length); -} - -unsigned strlcat(string &dest, const char *src, unsigned length) { - dest.reserve(length); - return strlcat(dest(), src, length); -} - string substr(const char *src, unsigned start, unsigned length) { string dest; if(length == ~0u) { //copy entire string - dest = src + start; + dest.reserve(strlen(src + start) + 1); + strcpy(dest(), src + start); } else { //copy partial string - strlcpy(dest, src + start, length + 1); + dest.reserve(length + 1); + strmcpy(dest(), src + start, length + 1); } return dest; } diff --git a/snesfilter/nall/string/variadic.hpp b/kaijuu/nall/string/variadic.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/variadic.hpp rename to kaijuu/nall/string/variadic.hpp diff --git a/snesfilter/nall/string/wildcard.hpp b/kaijuu/nall/string/wildcard.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/wildcard.hpp rename to kaijuu/nall/string/wildcard.hpp diff --git a/snesfilter/nall/string/wrapper.hpp b/kaijuu/nall/string/wrapper.hpp old mode 100755 new mode 100644 similarity index 97% rename from snesfilter/nall/string/wrapper.hpp rename to kaijuu/nall/string/wrapper.hpp index c02d5396..9845e0b7 --- a/snesfilter/nall/string/wrapper.hpp +++ b/kaijuu/nall/string/wrapper.hpp @@ -3,6 +3,7 @@ namespace nall { unsigned string::length() const { return strlen(data); } +unsigned string::capacity() const { return size; } template lstring string::split(const char *key) const { lstring result; result.split(key, data); return result; } template lstring string::isplit(const char *key) const { lstring result; result.isplit(key, data); return result; } diff --git a/snesfilter/nall/string/xml.hpp b/kaijuu/nall/string/xml-legacy.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/string/xml.hpp rename to kaijuu/nall/string/xml-legacy.hpp diff --git a/kaijuu/nall/string/xml.hpp b/kaijuu/nall/string/xml.hpp new file mode 100644 index 00000000..937436c8 --- /dev/null +++ b/kaijuu/nall/string/xml.hpp @@ -0,0 +1,250 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +//XML v1.0 subset parser +//revision 0.01 + +namespace nall { +namespace XML { + +struct Node { + string name; + string data; + bool attribute; + vector children; + + inline bool exists() const { + return !name.empty(); + } + + inline bool isName(char c) const { + if(c >= 'A' && c <= 'Z') return true; + if(c >= 'a' && c <= 'z') return true; + if(c >= '0' && c <= '9') return true; + if(c == '.' || c == '_') return true; + if(c == '?') return true; + return false; + } + + inline bool isWhitespace(char c) const { + if(c == ' ' || c == '\t') return true; + if(c == '\r' || c == '\n') return true; + return false; + } + + //copy part of string from source document into target string; decode markup while copying + inline void copy(string &target, const char *source, unsigned length) { + target.reserve(length + 1); + + #if defined(NALL_XML_LITERAL) + memcpy(target(), source, length); + target[length] = 0; + return; + #endif + + char *output = target(); + while(length) { + if(*source == '&') { + if(!memcmp(source, "<", 4)) { *output++ = '<'; source += 4; length -= 4; continue; } + if(!memcmp(source, ">", 4)) { *output++ = '>'; source += 4; length -= 4; continue; } + if(!memcmp(source, "&", 5)) { *output++ = '&'; source += 5; length -= 5; continue; } + if(!memcmp(source, "'", 6)) { *output++ = '\''; source += 6; length -= 6; continue; } + if(!memcmp(source, """, 6)) { *output++ = '\"'; source += 6; length -= 6; continue; } + } + + if(attribute == false && source[0] == '<' && source[1] == '!') { + //comment + if(!memcmp(source, "", 3)) source++, length--; + source += 3, length -= 3; + continue; + } + + //CDATA + if(!memcmp(source, "", 3)) *output++ = *source++, length--; + source += 3, length -= 3; + continue; + } + } + + *output++ = *source++, length--; + } + *output = 0; + } + + inline bool parseExpression(const char *&p) { + if(*(p + 1) != '!') return false; + + //comment + if(!memcmp(p, "", 3)) p++; + if(!*p) throw "unclosed comment"; + p += 3; + return true; + } + + //CDATA + if(!memcmp(p, "", 3)) p++; + if(!*p) throw "unclosed CDATA"; + p += 3; + return true; + } + + //DOCTYPE + if(!memcmp(p, "') counter--; + } while(counter); + return true; + } + + return false; + } + + //returns true if tag closes itself (); false if not () + inline bool parseHead(const char *&p) { + //parse name + const char *nameStart = ++p; //skip '<' + while(isName(*p)) p++; + const char *nameEnd = p; + copy(name, nameStart, nameEnd - nameStart); + if(name.empty()) throw "missing element name"; + + //parse attributes + while(*p) { + while(isWhitespace(*p)) p++; + if(!*p) throw "unclosed attribute"; + if(*p == '?' || *p == '/' || *p == '>') break; + + //parse attribute name + Node *attribute = new Node; + children.append(attribute); + attribute->attribute = true; + + const char *nameStart = p; + while(isName(*p)) p++; + const char *nameEnd = p; + copy(attribute->name, nameStart, nameEnd - nameStart); + if(attribute->name.empty()) throw "missing attribute name"; + + //parse attribute data + if(*p++ != '=') throw "missing attribute value"; + char terminal = *p++; + if(terminal != '\'' && terminal != '\"') throw "attribute value not quoted"; + const char *dataStart = p; + while(*p && *p != terminal) p++; + if(!*p) throw "missing attribute data terminal"; + const char *dataEnd = p++; //skip closing terminal + + copy(attribute->data, dataStart, dataEnd - dataStart); + } + + //parse closure + if(*p == '?' && *(p + 1) == '>') { p += 2; return true; } + if(*p == '/' && *(p + 1) == '>') { p += 2; return true; } + if(*p == '>') { p += 1; return false; } + throw "invalid element tag"; + } + + //parse element and all of its child elements + inline void parseElement(const char *&p) { + Node *node = new Node; + children.append(node); + if(node->parseHead(p) == true) return; + node->parse(p); + } + + //return true if matches this node's name + inline bool parseClosureElement(const char *&p) { + if(p[0] != '<' || p[1] != '/') return false; + p += 2; + const char *nameStart = p; + while(*p && *p != '>') p++; + if(*p != '>') throw "unclosed closure element"; + const char *nameEnd = p++; + if(memcmp(name, nameStart, nameEnd - nameStart)) throw "closure element name mismatch"; + return true; + } + + //parse contents of an element + inline void parse(const char *&p) { + const char *dataStart = p, *dataEnd = p; + + while(*p) { + while(*p && *p != '<') p++; + if(!*p) break; + dataEnd = p; + if(parseClosureElement(p) == true) break; + if(parseExpression(p) == true) continue; + parseElement(p); + } + + copy(data, dataStart, dataEnd - dataStart); + } + + inline void reset() { + for(auto &child : children) delete child; + children.reset(); + } + + struct iterator { + inline bool operator!=(const iterator &source) const { return index != source.index; } + inline Node& operator*() { return *node.children[index]; } + inline iterator& operator++() { index++; return *this; } + inline iterator(const Node &node, unsigned index) : node(node), index(index) {} + private: + const Node &node; + unsigned index; + }; + + inline iterator begin() { return iterator(*this, 0); } + inline iterator end() { return iterator(*this, children.size()); } + inline const iterator begin() const { return iterator(*this, 0); } + inline const iterator end() const { return iterator(*this, children.size()); } + + inline Node& operator[](const char *name) { + for(auto &node : *this) { + if(node.name == name) return node; + } + static Node node; + return node; + } + + inline Node() : attribute(false) {} + inline ~Node() { reset(); } + + Node(const Node&) = delete; + Node& operator=(const Node&) = delete; +}; + +struct Document : Node { + string error; + + inline bool load(const char *document) { + if(document == nullptr) return false; + reset(); + try { + parse(document); + } catch(const char *error) { + reset(); + this->error = error; + return false; + } + return true; + } + + inline Document() {} + inline Document(const char *document) { load(document); } +}; + +} +} + +#endif diff --git a/kaijuu/nall/traits.hpp b/kaijuu/nall/traits.hpp new file mode 100644 index 00000000..6a140c2b --- /dev/null +++ b/kaijuu/nall/traits.hpp @@ -0,0 +1,33 @@ +#ifndef NALL_TRAITS_HPP +#define NALL_TRAITS_HPP + +#include + +namespace nall { + +template class has_default_constructor { + template class receive_size{}; + template static signed sfinae(receive_size*); + template static char sfinae(...); + +public: + enum : bool { value = sizeof(sfinae(0)) == sizeof(signed) }; +}; + +template struct enable_if { typedef T type; }; +template struct enable_if {}; + +template struct type_if { typedef T type; }; +template struct type_if { typedef F type; }; + +template struct static_and { enum { value = false }; }; +template<> struct static_and { enum { value = true }; }; + +template struct static_or { enum { value = false }; }; +template<> struct static_or { enum { value = true }; }; +template<> struct static_or { enum { value = true }; }; +template<> struct static_or { enum { value = true }; }; + +} + +#endif diff --git a/kaijuu/nall/udl.hpp b/kaijuu/nall/udl.hpp new file mode 100644 index 00000000..30ceefb3 --- /dev/null +++ b/kaijuu/nall/udl.hpp @@ -0,0 +1,28 @@ +#ifndef NALL_UDL_HPP +#define NALL_UDL_HPP + +//user-defined literals + +#include +#include + +namespace nall { + constexpr inline uintmax_t operator"" _b(const char *n) { return binary(n); } + + //convert to bytes + constexpr inline uintmax_t operator"" _kb(unsigned long long n) { return 1024 * n; } + constexpr inline uintmax_t operator"" _mb(unsigned long long n) { return 1024 * 1024 * n; } + constexpr inline uintmax_t operator"" _gb(unsigned long long n) { return 1024 * 1024 * 1024 * n; } + + //convert to bits + constexpr inline uintmax_t operator"" _kbit(unsigned long long n) { return 1024 * n / 8; } + constexpr inline uintmax_t operator"" _mbit(unsigned long long n) { return 1024 * 1024 * n / 8; } + constexpr inline uintmax_t operator"" _gbit(unsigned long long n) { return 1024 * 1024 * 1024 * n / 8; } + + //convert to hz + constexpr inline uintmax_t operator"" _khz(long double n) { return n * 1000; } + constexpr inline uintmax_t operator"" _mhz(long double n) { return n * 1000000; } + constexpr inline uintmax_t operator"" _ghz(long double n) { return n * 1000000000; } +} + +#endif diff --git a/snesfilter/nall/ups.hpp b/kaijuu/nall/ups.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/ups.hpp rename to kaijuu/nall/ups.hpp diff --git a/snesfilter/nall/utility.hpp b/kaijuu/nall/utility.hpp old mode 100755 new mode 100644 similarity index 71% rename from snesfilter/nall/utility.hpp rename to kaijuu/nall/utility.hpp index ff8d8bee..b3c1e5aa --- a/snesfilter/nall/utility.hpp +++ b/kaijuu/nall/utility.hpp @@ -5,16 +5,6 @@ #include namespace nall { - template struct enable_if { typedef T type; }; - template struct enable_if {}; - template struct mp_enable_if : enable_if {}; - - template inline void swap(T &x, T &y) { - T temp(std::move(x)); - x = std::move(y); - y = std::move(temp); - } - template struct base_from_member { T value; base_from_member(T value_) : value(value_) {} diff --git a/kaijuu/nall/varint.hpp b/kaijuu/nall/varint.hpp new file mode 100644 index 00000000..98e189db --- /dev/null +++ b/kaijuu/nall/varint.hpp @@ -0,0 +1,168 @@ +#ifndef NALL_VARINT_HPP +#define NALL_VARINT_HPP + +#include +#include + +namespace nall { + template struct uint_t { + private: + typedef typename type_if::type type_t; + type_t data; + + public: + inline operator type_t() const { return data; } + inline type_t operator ++(int) { type_t r = data; data = uclip(data + 1); return r; } + inline type_t operator --(int) { type_t r = data; data = uclip(data - 1); return r; } + inline type_t operator ++() { return data = uclip(data + 1); } + inline type_t operator --() { return data = uclip(data - 1); } + inline type_t operator =(const type_t i) { return data = uclip(i); } + inline type_t operator |=(const type_t i) { return data = uclip(data | i); } + inline type_t operator ^=(const type_t i) { return data = uclip(data ^ i); } + inline type_t operator &=(const type_t i) { return data = uclip(data & i); } + inline type_t operator<<=(const type_t i) { return data = uclip(data << i); } + inline type_t operator>>=(const type_t i) { return data = uclip(data >> i); } + inline type_t operator +=(const type_t i) { return data = uclip(data + i); } + inline type_t operator -=(const type_t i) { return data = uclip(data - i); } + inline type_t operator *=(const type_t i) { return data = uclip(data * i); } + inline type_t operator /=(const type_t i) { return data = uclip(data / i); } + inline type_t operator %=(const type_t i) { return data = uclip(data % i); } + + inline uint_t() : data(0) {} + inline uint_t(const type_t i) : data(uclip(i)) {} + + template inline type_t operator=(const uint_t &i) { return data = uclip((type_t)i); } + template inline uint_t(const uint_t &i) : data(uclip(i)) {} + }; + + template struct int_t { + private: + typedef typename type_if::type type_t; + type_t data; + + public: + inline operator type_t() const { return data; } + inline type_t operator ++(int) { type_t r = data; data = sclip(data + 1); return r; } + inline type_t operator --(int) { type_t r = data; data = sclip(data - 1); return r; } + inline type_t operator ++() { return data = sclip(data + 1); } + inline type_t operator --() { return data = sclip(data - 1); } + inline type_t operator =(const type_t i) { return data = sclip(i); } + inline type_t operator |=(const type_t i) { return data = sclip(data | i); } + inline type_t operator ^=(const type_t i) { return data = sclip(data ^ i); } + inline type_t operator &=(const type_t i) { return data = sclip(data & i); } + inline type_t operator<<=(const type_t i) { return data = sclip(data << i); } + inline type_t operator>>=(const type_t i) { return data = sclip(data >> i); } + inline type_t operator +=(const type_t i) { return data = sclip(data + i); } + inline type_t operator -=(const type_t i) { return data = sclip(data - i); } + inline type_t operator *=(const type_t i) { return data = sclip(data * i); } + inline type_t operator /=(const type_t i) { return data = sclip(data / i); } + inline type_t operator %=(const type_t i) { return data = sclip(data % i); } + + inline int_t() : data(0) {} + inline int_t(const type_t i) : data(sclip(i)) {} + + template inline type_t operator=(const int_t &i) { return data = sclip((type_t)i); } + template inline int_t(const int_t &i) : data(sclip(i)) {} + }; + + template struct varuint_t { + private: + type_t data; + type_t mask; + + public: + inline operator type_t() const { return data; } + inline type_t operator ++(int) { type_t r = data; data = (data + 1) & mask; return r; } + inline type_t operator --(int) { type_t r = data; data = (data - 1) & mask; return r; } + inline type_t operator ++() { return data = (data + 1) & mask; } + inline type_t operator --() { return data = (data - 1) & mask; } + inline type_t operator =(const type_t i) { return data = (i) & mask; } + inline type_t operator |=(const type_t i) { return data = (data | i) & mask; } + inline type_t operator ^=(const type_t i) { return data = (data ^ i) & mask; } + inline type_t operator &=(const type_t i) { return data = (data & i) & mask; } + inline type_t operator<<=(const type_t i) { return data = (data << i) & mask; } + inline type_t operator>>=(const type_t i) { return data = (data >> i) & mask; } + inline type_t operator +=(const type_t i) { return data = (data + i) & mask; } + inline type_t operator -=(const type_t i) { return data = (data - i) & mask; } + inline type_t operator *=(const type_t i) { return data = (data * i) & mask; } + inline type_t operator /=(const type_t i) { return data = (data / i) & mask; } + inline type_t operator %=(const type_t i) { return data = (data % i) & mask; } + + inline void bits(type_t bits) { mask = (1ull << (bits - 1)) + ((1ull << (bits - 1)) - 1); data &= mask; } + inline varuint_t() : data(0ull), mask((type_t)~0ull) {} + inline varuint_t(const type_t i) : data(i), mask((type_t)~0ull) {} + }; +} + +//typedefs + typedef nall::uint_t< 1> uint1_t; + typedef nall::uint_t< 2> uint2_t; + typedef nall::uint_t< 3> uint3_t; + typedef nall::uint_t< 4> uint4_t; + typedef nall::uint_t< 5> uint5_t; + typedef nall::uint_t< 6> uint6_t; + typedef nall::uint_t< 7> uint7_t; +//typedef nall::uint_t< 8> uint8_t; + + typedef nall::uint_t< 9> uint9_t; + typedef nall::uint_t<10> uint10_t; + typedef nall::uint_t<11> uint11_t; + typedef nall::uint_t<12> uint12_t; + typedef nall::uint_t<13> uint13_t; + typedef nall::uint_t<14> uint14_t; + typedef nall::uint_t<15> uint15_t; +//typedef nall::uint_t<16> uint16_t; + + typedef nall::uint_t<17> uint17_t; + typedef nall::uint_t<18> uint18_t; + typedef nall::uint_t<19> uint19_t; + typedef nall::uint_t<20> uint20_t; + typedef nall::uint_t<21> uint21_t; + typedef nall::uint_t<22> uint22_t; + typedef nall::uint_t<23> uint23_t; + typedef nall::uint_t<24> uint24_t; + typedef nall::uint_t<25> uint25_t; + typedef nall::uint_t<26> uint26_t; + typedef nall::uint_t<27> uint27_t; + typedef nall::uint_t<28> uint28_t; + typedef nall::uint_t<29> uint29_t; + typedef nall::uint_t<30> uint30_t; + typedef nall::uint_t<31> uint31_t; +//typedef nall::uint_t<32> uint32_t; + + typedef nall::int_t< 1> int1_t; + typedef nall::int_t< 2> int2_t; + typedef nall::int_t< 3> int3_t; + typedef nall::int_t< 4> int4_t; + typedef nall::int_t< 5> int5_t; + typedef nall::int_t< 6> int6_t; + typedef nall::int_t< 7> int7_t; +//typedef nall::int_t< 8> int8_t; + + typedef nall::int_t< 9> int9_t; + typedef nall::int_t<10> int10_t; + typedef nall::int_t<11> int11_t; + typedef nall::int_t<12> int12_t; + typedef nall::int_t<13> int13_t; + typedef nall::int_t<14> int14_t; + typedef nall::int_t<15> int15_t; +//typedef nall::int_t<16> int16_t; + + typedef nall::int_t<17> int17_t; + typedef nall::int_t<18> int18_t; + typedef nall::int_t<19> int19_t; + typedef nall::int_t<20> int20_t; + typedef nall::int_t<21> int21_t; + typedef nall::int_t<22> int22_t; + typedef nall::int_t<23> int23_t; + typedef nall::int_t<24> int24_t; + typedef nall::int_t<25> int25_t; + typedef nall::int_t<26> int26_t; + typedef nall::int_t<27> int27_t; + typedef nall::int_t<28> int28_t; + typedef nall::int_t<29> int29_t; + typedef nall::int_t<30> int30_t; + typedef nall::int_t<31> int31_t; +//typedef nall::int_t<32> int32_t; + +#endif diff --git a/kaijuu/nall/vector.hpp b/kaijuu/nall/vector.hpp new file mode 100644 index 00000000..13200ea6 --- /dev/null +++ b/kaijuu/nall/vector.hpp @@ -0,0 +1,204 @@ +#ifndef NALL_VECTOR_HPP +#define NALL_VECTOR_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nall { + template struct vector { + struct exception_out_of_bounds{}; + + protected: + T *pool; + unsigned poolsize; + unsigned objectsize; + + public: + operator bool() const { return pool; } + T* data() { return pool; } + + bool empty() const { return objectsize == 0; } + unsigned size() const { return objectsize; } + unsigned capacity() const { return poolsize; } + + T* move() { + T *result = pool; + pool = nullptr; + poolsize = 0; + objectsize = 0; + return result; + } + + void reset() { + if(pool) { + for(unsigned n = 0; n < objectsize; n++) pool[n].~T(); + free(pool); + } + pool = nullptr; + poolsize = 0; + objectsize = 0; + } + + void reserve(unsigned size) { + size = bit::round(size); //amortize growth + T *copy = (T*)calloc(size, sizeof(T)); + for(unsigned n = 0; n < min(size, objectsize); n++) new(copy + n) T(pool[n]); + for(unsigned n = 0; n < objectsize; n++) pool[n].~T(); + free(pool); + pool = copy; + poolsize = size; + objectsize = min(size, objectsize); + } + + //requires trivial constructor + void resize(unsigned size) { + if(size == objectsize) return; + if(size < objectsize) return reserve(size); + while(size > objectsize) append(T()); + } + + template + void append(const T& data, Args&&... args) { + append(data); + append(std::forward(args)...); + } + + void append(const T& data) { + if(objectsize + 1 > poolsize) reserve(objectsize + 1); + new(pool + objectsize++) T(data); + } + + bool appendonce(const T& data) { + if(find(data) == true) return false; + append(data); + return true; + } + + void insert(unsigned position, const T& data) { + append(data); + for(signed n = size() - 1; n > position; n--) pool[n] = pool[n - 1]; + pool[position] = data; + } + + void prepend(const T& data) { + insert(0, data); + } + + void remove(unsigned index = ~0u, unsigned count = 1) { + if(index == ~0) index = objectsize ? objectsize - 1 : 0; + for(unsigned n = index; count + n < objectsize; n++) pool[n] = pool[count + n]; + objectsize = (count + index >= objectsize) ? index : objectsize - count; + } + + T take(unsigned index = ~0u) { + if(index == ~0) index = objectsize ? objectsize - 1 : 0; + if(index >= objectsize) throw exception_out_of_bounds(); + T item = pool[index]; + remove(index); + return item; + } + + void reverse() { + unsigned pivot = size() / 2; + for(unsigned l = 0, r = size() - 1; l < pivot; l++, r--) { + std::swap(pool[l], pool[r]); + } + } + + void sort() { + nall::sort(pool, objectsize); + } + + template void sort(const Comparator &lessthan) { + nall::sort(pool, objectsize, lessthan); + } + + optional find(const T& data) { + for(unsigned n = 0; n < size(); n++) if(pool[n] == data) return { true, n }; + return { false, 0u }; + } + + T& first() { + if(objectsize == 0) throw exception_out_of_bounds(); + return pool[0]; + } + + T& last() { + if(objectsize == 0) throw exception_out_of_bounds(); + return pool[objectsize - 1]; + } + + //access + inline T& operator[](unsigned position) { + if(position >= objectsize) throw exception_out_of_bounds(); + return pool[position]; + } + + inline const T& operator[](unsigned position) const { + if(position >= objectsize) throw exception_out_of_bounds(); + return pool[position]; + } + + inline T& operator()(unsigned position) { + if(position >= poolsize) reserve(position + 1); + while(position >= objectsize) append(T()); + return pool[position]; + } + + inline const T& operator()(unsigned position, const T& data) const { + if(position >= objectsize) return data; + return pool[position]; + } + + //iteration + T* begin() { return &pool[0]; } + T* end() { return &pool[objectsize]; } + const T* begin() const { return &pool[0]; } + const T* end() const { return &pool[objectsize]; } + + //copy + inline vector& operator=(const vector &source) { + reset(); + reserve(source.capacity()); + for(auto &data : source) append(data); + return *this; + } + + vector(const vector &source) : pool(nullptr), poolsize(0), objectsize(0) { + operator=(source); + } + + //move + inline vector& operator=(vector &&source) { + reset(); + pool = source.pool, poolsize = source.poolsize, objectsize = source.objectsize; + source.pool = nullptr, source.poolsize = 0, source.objectsize = 0; + return *this; + } + + vector(vector &&source) : pool(nullptr), poolsize(0), objectsize(0) { + operator=(std::move(source)); + } + + //construction + vector() : pool(nullptr), poolsize(0), objectsize(0) { + } + + vector(std::initializer_list list) : pool(nullptr), poolsize(0), objectsize(0) { + for(auto &data : list) append(data); + } + + ~vector() { + reset(); + } + }; +} + +#endif diff --git a/snesfilter/nall/windows/detour.hpp b/kaijuu/nall/windows/detour.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/windows/detour.hpp rename to kaijuu/nall/windows/detour.hpp diff --git a/kaijuu/nall/windows/guid.hpp b/kaijuu/nall/windows/guid.hpp new file mode 100644 index 00000000..386cfc75 --- /dev/null +++ b/kaijuu/nall/windows/guid.hpp @@ -0,0 +1,30 @@ +#ifndef NALL_WINDOWS_GUID_HPP +#define NALL_WINDOWS_GUID_HPP + +#include +#include + +namespace nall { + +//generate unique GUID +inline string guid() { + random_lfsr lfsr; + lfsr.seed(time(0)); + for(unsigned n = 0; n < 256; n++) lfsr(); + + string output; + for(unsigned n = 0; n < 4; n++) output.append(hex<2>(lfsr())); + output.append("-"); + for(unsigned n = 0; n < 2; n++) output.append(hex<2>(lfsr())); + output.append("-"); + for(unsigned n = 0; n < 2; n++) output.append(hex<2>(lfsr())); + output.append("-"); + for(unsigned n = 0; n < 2; n++) output.append(hex<2>(lfsr())); + output.append("-"); + for(unsigned n = 0; n < 6; n++) output.append(hex<2>(lfsr())); + return {"{", output, "}"}; +} + +} + +#endif diff --git a/snesfilter/nall/windows/launcher.hpp b/kaijuu/nall/windows/launcher.hpp old mode 100755 new mode 100644 similarity index 100% rename from snesfilter/nall/windows/launcher.hpp rename to kaijuu/nall/windows/launcher.hpp diff --git a/kaijuu/nall/windows/registry.hpp b/kaijuu/nall/windows/registry.hpp new file mode 100644 index 00000000..0774e04a --- /dev/null +++ b/kaijuu/nall/windows/registry.hpp @@ -0,0 +1,120 @@ +#ifndef NALL_WINDOWS_REGISTRY_HPP +#define NALL_WINDOWS_REGISTRY_HPP + +#include +#include + +#include +#ifndef KEY_WOW64_64KEY + #define KEY_WOW64_64KEY 0x0100 +#endif +#ifndef KEY_WOW64_32KEY + #define KEY_WOW64_32KEY 0x0200 +#endif + +#ifndef NWR_FLAGS + #define NWR_FLAGS KEY_WOW64_64KEY +#endif + +#ifndef NWR_SIZE + #define NWR_SIZE 4096 +#endif + +namespace nall { + +struct registry { + static bool exists(const string &name) { + lstring part = name.split("/"); + HKEY handle, rootKey = root(part.take(0)); + string node = part.take(); + string path = part.concatenate("\\"); + if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { + wchar_t data[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + LONG result = RegQueryValueExW(handle, utf16_t(node), NULL, NULL, (LPBYTE)&data, (LPDWORD)&size); + RegCloseKey(handle); + if(result == ERROR_SUCCESS) return true; + } + return false; + } + + static string read(const string &name) { + lstring part = name.split("/"); + HKEY handle, rootKey = root(part.take(0)); + string node = part.take(); + string path = part.concatenate("\\"); + if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { + wchar_t data[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + LONG result = RegQueryValueExW(handle, utf16_t(node), NULL, NULL, (LPBYTE)&data, (LPDWORD)&size); + RegCloseKey(handle); + if(result == ERROR_SUCCESS) return (const char*)utf8_t(data); + } + return ""; + } + + static void write(const string &name, const string &data = "") { + lstring part = name.split("/"); + HKEY handle, rootKey = root(part.take(0)); + string node = part.take(), path; + DWORD disposition; + for(unsigned n = 0; n < part.size(); n++) { + path.append(part[n]); + if(RegCreateKeyExW(rootKey, utf16_t(path), 0, NULL, 0, NWR_FLAGS | KEY_ALL_ACCESS, NULL, &handle, &disposition) == ERROR_SUCCESS) { + if(n == part.size() - 1) { + RegSetValueExW(handle, utf16_t(node), 0, REG_SZ, (BYTE*)(wchar_t*)utf16_t(data), (data.length() + 1) * sizeof(wchar_t)); + } + RegCloseKey(handle); + } + path.append("\\"); + } + } + + static bool remove(const string &name) { + lstring part = name.split("/"); + HKEY rootKey = root(part.take(0)); + string node = part.take(); + string path = part.concatenate("\\"); + if(node.empty()) return SHDeleteKeyW(rootKey, utf16_t(path)) == ERROR_SUCCESS; + return SHDeleteValueW(rootKey, utf16_t(path), utf16_t(node)) == ERROR_SUCCESS; + } + + static lstring contents(const string &name) { + lstring part = name.split("/"), result; + HKEY handle, rootKey = root(part.take(0)); + part.remove(); + string path = part.concatenate("\\"); + if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { + DWORD folders, nodes; + RegQueryInfoKey(handle, NULL, NULL, NULL, &folders, NULL, NULL, &nodes, NULL, NULL, NULL, NULL); + for(unsigned n = 0; n < folders; n++) { + wchar_t name[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + RegEnumKeyEx(handle, n, (wchar_t*)&name, &size, NULL, NULL, NULL, NULL); + result.append({(const char*)utf8_t(name), "/"}); + } + for(unsigned n = 0; n < nodes; n++) { + wchar_t name[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + RegEnumValueW(handle, n, (wchar_t*)&name, &size, NULL, NULL, NULL, NULL); + result.append((const char*)utf8_t(name)); + } + RegCloseKey(handle); + } + return result; + } + +private: + static HKEY root(const string &name) { + if(name == "HKCR") return HKEY_CLASSES_ROOT; + if(name == "HKCC") return HKEY_CURRENT_CONFIG; + if(name == "HKCU") return HKEY_CURRENT_USER; + if(name == "HKLM") return HKEY_LOCAL_MACHINE; + if(name == "HKU" ) return HKEY_USERS; + return NULL; + } +}; + +} + +#endif diff --git a/snesfilter/nall/windows/utf8.hpp b/kaijuu/nall/windows/utf8.hpp old mode 100755 new mode 100644 similarity index 98% rename from snesfilter/nall/windows/utf8.hpp rename to kaijuu/nall/windows/utf8.hpp index f5597b85..b1374943 --- a/snesfilter/nall/windows/utf8.hpp +++ b/kaijuu/nall/windows/utf8.hpp @@ -12,6 +12,7 @@ #define UNICODE #define _WIN32_WINNT 0x0501 #define NOMINMAX +#include #include #undef interface diff --git a/kaijuu/nall/xorg/guard.hpp b/kaijuu/nall/xorg/guard.hpp new file mode 100644 index 00000000..a1282683 --- /dev/null +++ b/kaijuu/nall/xorg/guard.hpp @@ -0,0 +1,29 @@ +#ifndef NALL_XORG_GUARD_HPP +#define NALL_XORG_GUARD_HPP + +#define None +#undef XlibNone +#define XlibNone 0L +#define Button1 XlibButton1 +#define Button2 XlibButton2 +#define Button3 XlibButton3 +#define Button4 XlibButton4 +#define Button5 XlibButton5 +#define Display XlibDisplay +#define Screen XlibScreen +#define Window XlibWindow + +#else +#undef NALL_XORG_GUARD_HPP + +#undef None +#undef Button1 +#undef Button2 +#undef Button3 +#undef Button4 +#undef Button5 +#undef Display +#undef Screen +#undef Window + +#endif diff --git a/kaijuu/nall/xorg/xorg.hpp b/kaijuu/nall/xorg/xorg.hpp new file mode 100644 index 00000000..bcf48b46 --- /dev/null +++ b/kaijuu/nall/xorg/xorg.hpp @@ -0,0 +1,12 @@ +#ifndef NALL_XORG_XORG_HPP +#define NALL_XORG_XORG_HPP + +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/snesfilter/nall/zip.hpp b/kaijuu/nall/zip.hpp old mode 100755 new mode 100644 similarity index 79% rename from snesfilter/nall/zip.hpp rename to kaijuu/nall/zip.hpp index ad9c7506..779b067e --- a/snesfilter/nall/zip.hpp +++ b/kaijuu/nall/zip.hpp @@ -37,6 +37,14 @@ struct zip { file.reset(); const uint8_t *footer = data + size - 22; + while(true) { + if(footer <= data + 22) return false; + if(read(footer, 4) == 0x06054b50) { + unsigned commentlength = read(footer + 20, 2); + if(footer + 22 + commentlength == data + size) break; + } + footer--; + } const uint8_t *directory = data + read(footer + 16, 4); while(true) { @@ -72,28 +80,22 @@ struct zip { return true; } - inline bool extract(File &file, uint8_t *&data, unsigned &size) { - data = 0, size = 0; + inline vector extract(File &file) { + vector buffer; if(file.cmode == 0) { - size = file.size; - data = new uint8_t[size]; - memcpy(data, file.data, size); - return true; + buffer.resize(file.size); + memcpy(buffer.data(), file.data, file.size); } if(file.cmode == 8) { - size = file.size; - data = new uint8_t[size]; - if(inflate(data, size, file.data, file.csize) == false) { - delete[] data; - size = 0; - return false; + buffer.resize(file.size); + if(inflate(buffer.data(), buffer.size(), file.data, file.csize) == false) { + buffer.reset(); } - return true; } - return false; + return buffer; } inline void close() { @@ -116,7 +118,7 @@ protected: } public: - linear_vector file; + vector file; }; } diff --git a/kaijuu/phoenix/Makefile b/kaijuu/phoenix/Makefile new file mode 100644 index 00000000..d1c9d981 --- /dev/null +++ b/kaijuu/phoenix/Makefile @@ -0,0 +1,21 @@ +ifeq ($(platform),x) + ifeq ($(phoenix),) + phoenix := gtk + endif + + ifeq ($(phoenix),gtk) + phoenixflags := -DPHOENIX_GTK `pkg-config --cflags gtk+-2.0` + phoenixlink := `pkg-config --libs gtk+-2.0` + endif + + ifeq ($(phoenix),qt) + phoenixflags := -DPHOENIX_QT `pkg-config --cflags QtCore QtGui` + phoenixlink := `pkg-config --libs QtCore QtGui` + endif +else ifeq ($(platform),win) + phoenixflags := -DPHOENIX_WINDOWS + phoenixlink := -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -lshlwapi +else + phoenixflags := -DPHOENIX_REFERENCE + phoenixlink := +endif diff --git a/kaijuu/phoenix/core/core.cpp b/kaijuu/phoenix/core/core.cpp new file mode 100644 index 00000000..a6a1ce38 --- /dev/null +++ b/kaijuu/phoenix/core/core.cpp @@ -0,0 +1,1326 @@ +#include "state.hpp" +#include "layout/fixed-layout.cpp" +#include "layout/horizontal-layout.cpp" +#include "layout/vertical-layout.cpp" + +#if defined(PHOENIX_WINDOWS) + #include "../windows/platform.cpp" +#elif defined(PHOENIX_QT) + #include "../qt/platform.cpp" +#elif defined(PHOENIX_GTK) + #include "../gtk/platform.cpp" +#elif defined(PHOENIX_REFERENCE) + #include "../reference/platform.cpp" +#endif + +static bool OS_quit = false; + +//Color +//===== + +uint32_t Color::rgb() const { + return (255 << 24) + (red << 16) + (green << 8) + (blue << 0); +} + +uint32_t Color::rgba() const { + return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0); +} + +//Geometry +//======== + +Position Geometry::position() const { + return { x, y }; +} + +Size Geometry::size() const { + return { width, height }; +} + +string Geometry::text() const { + return { x, ",", y, ",", width, ",", height }; +} + +Geometry::Geometry(const string &text) { + lstring part = text.split(","); + x = integer(part(0, "256")); + y = integer(part(1, "256")); + width = decimal(part(2, "256")); + height = decimal(part(3, "256")); +} + +//Font +//==== + +Geometry Font::geometry(const string &text) { + return pFont::geometry(description, text); +} + +Font::Font(const string &description): +description(description) { +} + +//Desktop +//======= + +Size Desktop::size() { + return pDesktop::size(); +} + +Geometry Desktop::workspace() { + return pDesktop::workspace(); +} + +//Keyboard +//======== + +bool Keyboard::pressed(Keyboard::Scancode scancode) { + return pKeyboard::pressed(scancode); +} + +bool Keyboard::released(Keyboard::Scancode scancode) { + return !pressed(scancode); +} + +vector Keyboard::state() { + return pKeyboard::state(); +} + +//Mouse +//===== + +Position Mouse::position() { + return pMouse::position(); +} + +bool Mouse::pressed(Mouse::Button button) { + return pMouse::pressed(button); +} + +bool Mouse::released(Mouse::Button button) { + return !pressed(button); +} + +//DialogWindow +//============ + +string DialogWindow::fileOpen_(Window &parent, const string &path, const lstring &filter_) { + auto filter = filter_; + if(filter.size() == 0) filter.append("All files (*)"); + return pDialogWindow::fileOpen(parent, path, filter); +} + +string DialogWindow::fileSave_(Window &parent, const string &path, const lstring &filter_) { + auto filter = filter_; + if(filter.size() == 0) filter.append("All files (*)"); + return pDialogWindow::fileSave(parent, path, filter); +} + +string DialogWindow::folderSelect(Window &parent, const string &path) { + return pDialogWindow::folderSelect(parent, path); +} + +//MessageWindow +//============= + +MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::information(parent, text, buttons); +} + +MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::question(parent, text, buttons); +} + +MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::warning(parent, text, buttons); +} + +MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::critical(parent, text, buttons); +} + +//Object +//====== + +Object::Object(pObject &p): +p(p) { + OS::initialize(); + p.constructor(); +} + +Object::~Object() { + p.destructor(); + delete &p; +} + +//OS +//== + +void OS::main() { + return pOS::main(); +} + +bool OS::pendingEvents() { + return pOS::pendingEvents(); +} + +void OS::processEvents() { + return pOS::processEvents(); +} + +void OS::quit() { + OS_quit = true; + return pOS::quit(); +} + +void OS::initialize() { + static bool initialized = false; + if(initialized == false) { + initialized = true; + return pOS::initialize(); + } +} + +//Timer +//===== + +void Timer::setEnabled(bool enabled) { + state.enabled = enabled; + return p.setEnabled(enabled); +} + +void Timer::setInterval(unsigned milliseconds) { + state.milliseconds = milliseconds; + return p.setInterval(milliseconds); +} + +Timer::Timer(): +state(*new State), +base_from_member(*new pTimer(*this)), +Object(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Timer::~Timer() { + p.destructor(); + delete &state; +} + +//Window +//====== + +Window& Window::none() { + return pWindow::none(); +} + +void Window::append_(Layout &layout) { + if(state.layout.append(layout)) { + ((Sizable&)layout).state.window = this; + ((Sizable&)layout).state.layout = 0; + p.append(layout); + layout.synchronizeLayout(); + } +} + +void Window::append_(Menu &menu) { + if(state.menu.append(menu)) { + ((Action&)menu).state.window = this; + p.append(menu); + } +} + +void Window::append_(Widget &widget) { + if(state.widget.append(widget)) { + ((Sizable&)widget).state.window = this; + p.append(widget); + } +} + +Color Window::backgroundColor() { + return p.backgroundColor(); +} + +Geometry Window::frameGeometry() { + Geometry geometry = p.geometry(); + Geometry margin = p.frameMargin(); + return { + geometry.x - margin.x, geometry.y - margin.y, + geometry.width + margin.width, geometry.height + margin.height + }; +} + +Geometry Window::frameMargin() { + return p.frameMargin(); +} + +bool Window::focused() { + return p.focused(); +} + +bool Window::fullScreen() { + return state.fullScreen; +} + +Geometry Window::geometry() { + return p.geometry(); +} + +void Window::ignore() { + state.ignore = true; +} + +void Window::remove_(Layout &layout) { + if(state.layout.remove(layout)) { + p.remove(layout); + ((Sizable&)layout).state.window = 0; + } +} + +void Window::remove_(Menu &menu) { + if(state.menu.remove(menu)) { + p.remove(menu); + ((Action&)menu).state.window = 0; + } +} + +void Window::remove_(Widget &widget) { + if(state.widget.remove(widget)) { + p.remove(widget); + ((Sizable&)widget).state.window = 0; + } +} + +void Window::setBackgroundColor(const Color &color) { + state.backgroundColorOverride = true; + state.backgroundColor = color; + return p.setBackgroundColor(color); +} + +void Window::setFrameGeometry(const Geometry &geometry) { + Geometry margin = p.frameMargin(); + return setGeometry({ + geometry.x + margin.x, geometry.y + margin.y, + geometry.width - margin.width, geometry.height - margin.height + }); +} + +void Window::setFocused() { + return p.setFocused(); +} + +void Window::setFullScreen(bool fullScreen) { + state.fullScreen = fullScreen; + return p.setFullScreen(fullScreen); +} + +void Window::setGeometry(const Geometry &geometry) { + state.geometry = geometry; + return p.setGeometry(geometry); +} + +void Window::setMenuFont(const string &font) { + state.menuFont = font; + return p.setMenuFont(font); +} + +void Window::setMenuVisible(bool visible) { + state.menuVisible = visible; + return p.setMenuVisible(visible); +} + +void Window::setModal(bool modal) { + state.modal = modal; + return p.setModal(modal); +} + +void Window::setResizable(bool resizable) { + state.resizable = resizable; + return p.setResizable(resizable); +} + +void Window::setStatusFont(const string &font) { + state.statusFont = font; + return p.setStatusFont(font); +} + +void Window::setStatusText(const string &text) { + state.statusText = text; + return p.setStatusText(text); +} + +void Window::setStatusVisible(bool visible) { + state.statusVisible = visible; + return p.setStatusVisible(visible); +} + +void Window::setTitle(const string &text) { + state.title = text; + return p.setTitle(text); +} + +void Window::setVisible(bool visible) { + state.visible = visible; + synchronizeLayout(); + return p.setVisible(visible); +} + +void Window::setWidgetFont(const string &font) { + state.widgetFont = font; + return p.setWidgetFont(font); +} + +string Window::statusText() { + return state.statusText; +} + +void Window::synchronizeLayout() { + if(visible() && OS_quit == false) setGeometry(geometry()); +} + +bool Window::visible() { + return state.visible; +} + +Window::Window(): +state(*new State), +base_from_member(*new pWindow(*this)), +Object(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Window::~Window() { + p.destructor(); + delete &state; +} + +//Action +//====== + +bool Action::enabled() { + return state.enabled; +} + +void Action::setEnabled(bool enabled) { + state.enabled = enabled; + return p.setEnabled(enabled); +} + +void Action::setVisible(bool visible) { + state.visible = visible; + return p.setVisible(visible); +} + +bool Action::visible() { + return state.visible; +} + +Action::Action(pAction &p): +state(*new State), +Object(p), +p(p) { + p.constructor(); +} + +Action::~Action() { + p.destructor(); + delete &state; +} + +//Menu +//==== + +void Menu::append(const set &list) { + for(auto &action : list) { + if(state.action.append(action)) { + action.state.menu = this; + p.append(action); + } + } +} + +void Menu::remove(const set &list) { + for(auto &action : list) { + if(state.action.remove(action)) { + action.state.menu = 0; + return p.remove(action); + } + } +} + +void Menu::setImage(const image &image) { + state.image = image; + return p.setImage(image); +} + +void Menu::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Menu::Menu(): +state(*new State), +base_from_member(*new pMenu(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Menu::~Menu() { + p.destructor(); + delete &state; +} + +//Separator +//========= + +Separator::Separator(): +base_from_member(*new pSeparator(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Separator::~Separator() { + p.destructor(); +} + +//Item +//==== + +void Item::setImage(const image &image) { + state.image = image; + return p.setImage(image); +} + +void Item::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Item::Item(): +state(*new State), +base_from_member(*new pItem(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Item::~Item() { + p.destructor(); + delete &state; +} + +//CheckItem +//========= + +bool CheckItem::checked() { + return p.checked(); +} + +void CheckItem::setChecked(bool checked) { + state.checked = checked; + return p.setChecked(checked); +} + +void CheckItem::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +CheckItem::CheckItem(): +state(*new State), +base_from_member(*new pCheckItem(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +CheckItem::~CheckItem() { + p.destructor(); + delete &state; +} + +//RadioItem +//========= + +void RadioItem::group(const set &list) { + for(auto &item : list) item.p.setGroup(item.state.group = list); + if(list.size()) list[0].setChecked(); +} + +bool RadioItem::checked() { + return p.checked(); +} + +void RadioItem::setChecked() { + for(auto &item : state.group) item.state.checked = false; + state.checked = true; + return p.setChecked(); +} + +void RadioItem::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +string RadioItem::text() { + return state.text; +} + +RadioItem::RadioItem(): +state(*new State), +base_from_member(*new pRadioItem(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +RadioItem::~RadioItem() { + for(auto &item : state.group) { + if(&item != this) item.state.group.remove(*this); + } + p.destructor(); + delete &state; +} + +//Sizable +//======= + +Layout* Sizable::layout() { + return state.layout; +} + +Window* Sizable::window() { + if(state.layout) return state.layout->window(); + return state.window; +} + +Sizable::Sizable(pSizable &p): +state(*new State), +Object(p), +p(p) { + p.constructor(); +} + +Sizable::~Sizable() { + if(layout()) layout()->remove(*this); + p.destructor(); + delete &state; +} + +//Layout +//====== + +void Layout::append(Sizable &sizable) { + sizable.state.layout = this; + sizable.state.window = 0; + + if(dynamic_cast(&sizable)) { + Layout &layout = (Layout&)sizable; + layout.synchronizeLayout(); + } + + if(dynamic_cast(&sizable)) { + Widget &widget = (Widget&)sizable; + if(sizable.window()) sizable.window()->append(widget); + } +} + +void Layout::remove(Sizable &sizable) { + if(dynamic_cast(&sizable)) { + Widget &widget = (Widget&)sizable; + if(sizable.window()) sizable.window()->remove(widget); + } + + sizable.state.layout = 0; + sizable.state.window = 0; +} + +Layout::Layout(): +state(*new State), +base_from_member(*new pLayout(*this)), +Sizable(base_from_member::value), +p(base_from_member::value) { +} + +Layout::Layout(pLayout &p): +state(*new State), +base_from_member(p), +Sizable(p), +p(p) { +} + +Layout::~Layout() { + if(layout()) layout()->remove(*this); + else if(window()) window()->remove(*this); + p.destructor(); + delete &state; +} + +//Widget +//====== + +bool Widget::enabled() { + return state.enabled; +} + +string Widget::font() { + return state.font; +} + +Geometry Widget::geometry() { + return state.geometry; +} + +Geometry Widget::minimumGeometry() { + return p.minimumGeometry(); +} + +void Widget::setEnabled(bool enabled) { + state.enabled = enabled; + return p.setEnabled(enabled); +} + +void Widget::setFocused() { + return p.setFocused(); +} + +void Widget::setFont(const string &font) { + state.font = font; + return p.setFont(font); +} + +void Widget::setGeometry(const Geometry &geometry) { + state.geometry = geometry; + return p.setGeometry(geometry); +} + +void Widget::setVisible(bool visible) { + state.visible = visible; + return p.setVisible(visible); +} + +bool Widget::visible() { + return state.visible; +} + +Widget::Widget(): +state(*new State), +base_from_member(*new pWidget(*this)), +Sizable(base_from_member::value), +p(base_from_member::value) { + state.abstract = true; + p.constructor(); +} + +Widget::Widget(pWidget &p): +state(*new State), +base_from_member(p), +Sizable(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Widget::~Widget() { + p.destructor(); + delete &state; +} + +//Button +//====== + +void Button::setImage(const image &image, Orientation orientation) { + state.image = image; + state.orientation = orientation; + return p.setImage(image, orientation); +} + +void Button::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Button::Button(): +state(*new State), +base_from_member(*new pButton(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Button::~Button() { + p.destructor(); + delete &state; +} + +//Canvas +//====== + +uint32_t* Canvas::data() { + return state.data; +} + +bool Canvas::setImage(const nall::image &image) { + if(image.data == nullptr || image.width == 0 || image.height == 0) return false; + state.width = image.width; + state.height = image.height; + setSize({ state.width, state.height }); + memcpy(state.data, image.data, state.width * state.height * sizeof(uint32_t)); + return true; +} + +void Canvas::setSize(const Size &size) { + state.width = size.width; + state.height = size.height; + delete[] state.data; + state.data = new uint32_t[size.width * size.height]; + return p.setSize(size); +} + +Size Canvas::size() { + return { state.width, state.height }; +} + +void Canvas::update() { + return p.update(); +} + +Canvas::Canvas(): +state(*new State), +base_from_member(*new pCanvas(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + state.data = new uint32_t[state.width * state.height]; + p.constructor(); +} + +Canvas::~Canvas() { + p.destructor(); + delete[] state.data; + delete &state; +} + +//CheckBox +//======== + +bool CheckBox::checked() { + return p.checked(); +} + +void CheckBox::setChecked(bool checked) { + state.checked = checked; + return p.setChecked(checked); +} + +void CheckBox::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +CheckBox::CheckBox(): +state(*new State), +base_from_member(*new pCheckBox(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +CheckBox::~CheckBox() { + p.destructor(); + delete &state; +} + +//ComboBox +//======== + +void ComboBox::append_(const lstring &list) { + for(auto &text : list) { + state.text.append(text); + p.append(text); + } +} + +void ComboBox::modify(unsigned row, const string &text) { + state.text(row) = text; + p.modify(row, text); +} + +void ComboBox::remove(unsigned row) { + state.text.remove(row); + p.remove(row); +} + +void ComboBox::reset() { + state.selection = 0; + state.text.reset(); + return p.reset(); +} + +unsigned ComboBox::selection() { + return p.selection(); +} + +void ComboBox::setSelection(unsigned row) { + state.selection = row; + return p.setSelection(row); +} + +string ComboBox::text() { + return state.text(selection()); +} + +string ComboBox::text(unsigned row) { + return state.text(row); +} + +ComboBox::ComboBox(): +state(*new State), +base_from_member(*new pComboBox(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +ComboBox::~ComboBox() { + p.destructor(); + delete &state; +} + +//HexEdit +//======= + +void HexEdit::setColumns(unsigned columns) { + state.columns = columns; + return p.setColumns(columns); +} + +void HexEdit::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void HexEdit::setOffset(unsigned offset) { + state.offset = offset; + return p.setOffset(offset); +} + +void HexEdit::setRows(unsigned rows) { + state.rows = rows; + return p.setRows(rows); +} + +void HexEdit::update() { + return p.update(); +} + +HexEdit::HexEdit(): +state(*new State), +base_from_member(*new pHexEdit(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +HexEdit::~HexEdit() { + p.destructor(); + delete &state; +} + +//HorizontalScrollBar +//=================== + +unsigned HorizontalScrollBar::length() { + return state.length; +} + +unsigned HorizontalScrollBar::position() { + return p.position(); +} + +void HorizontalScrollBar::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void HorizontalScrollBar::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +HorizontalScrollBar::HorizontalScrollBar(): +state(*new State), +base_from_member(*new pHorizontalScrollBar(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +HorizontalScrollBar::~HorizontalScrollBar() { + p.destructor(); + delete &state; +} + +//HorizontalSlider +//================ + +unsigned HorizontalSlider::length() { + return state.length; +} + +unsigned HorizontalSlider::position() { + return p.position(); +} + +void HorizontalSlider::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void HorizontalSlider::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +HorizontalSlider::HorizontalSlider(): +state(*new State), +base_from_member(*new pHorizontalSlider(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +HorizontalSlider::~HorizontalSlider() { + p.destructor(); + delete &state; +} + +//Label +//===== + +void Label::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Label::Label(): +state(*new State), +base_from_member(*new pLabel(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Label::~Label() { + p.destructor(); + delete &state; +} + +//LineEdit +//======== + +void LineEdit::setEditable(bool editable) { + state.editable = editable; + return p.setEditable(editable); +} + +void LineEdit::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +string LineEdit::text() { + return p.text(); +} + +LineEdit::LineEdit(): +state(*new State), +base_from_member(*new pLineEdit(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +LineEdit::~LineEdit() { + p.destructor(); + delete &state; +} + +//ListView +//======== + +void ListView::append_(const lstring &text) { + state.checked.append(false); + state.text.append(text); + return p.append(text); +} + +void ListView::autoSizeColumns() { + return p.autoSizeColumns(); +} + +bool ListView::checked(unsigned row) { + return p.checked(row); +} + +void ListView::modify_(unsigned row, const lstring &text) { + state.text[row] = text; + return p.modify(row, text); +} + +void ListView::remove(unsigned row) { + state.text.remove(row); + state.image.remove(row); + return p.remove(row); +} + +void ListView::reset() { + state.checked.reset(); + state.image.reset(); + state.text.reset(); + return p.reset(); +} + +bool ListView::selected() { + return p.selected(); +} + +unsigned ListView::selection() { + return p.selection(); +} + +void ListView::setCheckable(bool checkable) { + state.checkable = checkable; + return p.setCheckable(checkable); +} + +void ListView::setChecked(unsigned row, bool checked) { + state.checked[row] = checked; + return p.setChecked(row, checked); +} + +void ListView::setHeaderText_(const lstring &text) { + state.headerText = text; + return p.setHeaderText(text); +} + +void ListView::setHeaderVisible(bool visible) { + state.headerVisible = visible; + return p.setHeaderVisible(visible); +} + +void ListView::setImage(unsigned row, unsigned column, const nall::image &image) { + state.image(row)(column) = image; + return p.setImage(row, column, image); +} + +void ListView::setSelected(bool selected) { + state.selected = selected; + return p.setSelected(selected); +} + +void ListView::setSelection(unsigned row) { + state.selected = true; + state.selection = row; + return p.setSelection(row); +} + +ListView::ListView(): +state(*new State), +base_from_member(*new pListView(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +ListView::~ListView() { + p.destructor(); + delete &state; +} + +//ProgressBar +//=========== + +void ProgressBar::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +ProgressBar::ProgressBar(): +state(*new State), +base_from_member(*new pProgressBar(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +ProgressBar::~ProgressBar() { + p.destructor(); + delete &state; +} + +//RadioBox +//======== + +void RadioBox::group(const set &list) { + for(auto &item : list) item.p.setGroup(item.state.group = list); + if(list.size()) list[0].setChecked(); +} + +bool RadioBox::checked() { + return p.checked(); +} + +void RadioBox::setChecked() { + for(auto &item : state.group) item.state.checked = false; + state.checked = true; + return p.setChecked(); +} + +void RadioBox::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +RadioBox::RadioBox(): +state(*new State), +base_from_member(*new pRadioBox(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +RadioBox::~RadioBox() { + for(auto &item : state.group) { + if(&item != this) item.state.group.remove(*this); + } + p.destructor(); + delete &state; +} + +//TextEdit +//======== + +void TextEdit::setCursorPosition(unsigned position) { + state.cursorPosition = position; + return p.setCursorPosition(position); +} + +void TextEdit::setEditable(bool editable) { + state.editable = editable; + return p.setEditable(editable); +} + +void TextEdit::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +void TextEdit::setWordWrap(bool wordWrap) { + state.wordWrap = wordWrap; + return p.setWordWrap(wordWrap); +} + +string TextEdit::text() { + return p.text(); +} + +TextEdit::TextEdit(): +state(*new State), +base_from_member(*new pTextEdit(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +TextEdit::~TextEdit() { + p.destructor(); + delete &state; +} + +//VerticalScrollBar +//================= + +unsigned VerticalScrollBar::length() { + return state.length; +} + +unsigned VerticalScrollBar::position() { + return p.position(); +} + +void VerticalScrollBar::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void VerticalScrollBar::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +VerticalScrollBar::VerticalScrollBar(): +state(*new State), +base_from_member(*new pVerticalScrollBar(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +VerticalScrollBar::~VerticalScrollBar() { + p.destructor(); + delete &state; +} + +//VerticalSlider +//============== + +unsigned VerticalSlider::length() { + return state.length; +} + +unsigned VerticalSlider::position() { + return p.position(); +} + +void VerticalSlider::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void VerticalSlider::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +VerticalSlider::VerticalSlider(): +state(*new State), +base_from_member(*new pVerticalSlider(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +VerticalSlider::~VerticalSlider() { + p.destructor(); + delete &state; +} + +//Viewport +//======== + +uintptr_t Viewport::handle() { + return p.handle(); +} + +Viewport::Viewport(): +base_from_member(*new pViewport(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Viewport::~Viewport() { + p.destructor(); +} diff --git a/kaijuu/phoenix/core/core.hpp b/kaijuu/phoenix/core/core.hpp new file mode 100644 index 00000000..1e88ca5d --- /dev/null +++ b/kaijuu/phoenix/core/core.hpp @@ -0,0 +1,612 @@ +struct Font; +struct Window; +struct Menu; +struct Sizable; +struct Layout; +struct Widget; + +struct pFont; +struct pObject; +struct pOS; +struct pTimer; +struct pWindow; +struct pAction; +struct pMenu; +struct pSeparator; +struct pItem; +struct pCheckItem; +struct pRadioItem; +struct pSizable; +struct pLayout; +struct pWidget; +struct pButton; +struct pCanvas; +struct pCheckBox; +struct pComboBox; +struct pHexEdit; +struct pHorizontalScrollBar; +struct pHorizontalSlider; +struct pLabel; +struct pLineEdit; +struct pListView; +struct pProgressBar; +struct pRadioBox; +struct pTextEdit; +struct pVerticalScrollBar; +struct pVerticalSlider; +struct pViewport; + +enum : unsigned { + MaximumSize = ~0u, + MinimumSize = 0u, +}; + +struct Color { + uint8_t red, green, blue, alpha; + uint32_t rgb() const; + uint32_t rgba() const; + inline Color() : red(0), green(0), blue(0), alpha(255) {} + inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255) : red(red), green(green), blue(blue), alpha(alpha) {} +}; + +struct Position { + signed x, y; + inline Position() : x(0), y(0) {} + template inline Position(X x, Y y) : x(x), y(y) {} +}; + +struct Size { + unsigned width, height; + inline Size() : width(0), height(0) {} + template inline Size(W width, H height) : width(width), height(height) {} +}; + +struct Geometry { + signed x, y; + unsigned width, height; + Position position() const; + Size size() const; + nall::string text() const; + inline Geometry() : x(0), y(0), width(0), height(0) {} + inline Geometry(const Position& position, const Size& size) : x(position.x), y(position.y), width(size.width), height(size.height) {} + template inline Geometry(X x, Y y, W width, H height) : x(x), y(y), width(width), height(height) {} + Geometry(const nall::string &text); +}; + +enum class Orientation : unsigned { Horizontal, Vertical }; + +struct Font { + nall::string description; + Geometry geometry(const nall::string &text); + Font(const nall::string &description = ""); +}; + +struct Desktop { + static Size size(); + static Geometry workspace(); + Desktop() = delete; +}; + +struct Keyboard { + #include "keyboard.hpp" + static bool pressed(Scancode scancode); + static bool released(Scancode scancode); + static nall::vector state(); + Keyboard() = delete; +}; + +struct Mouse { + enum class Button : unsigned { Left, Middle, Right }; + static Position position(); + static bool pressed(Button); + static bool released(Button); + Mouse() = delete; +}; + +struct DialogWindow { + template static nall::string fileOpen(Window &parent, const nall::string &path, const Args&... args) { return fileOpen_(parent, path, { args... }); } + template static nall::string fileSave(Window &parent, const nall::string &path, const Args&... args) { return fileSave_(parent, path, { args... }); } + static nall::string folderSelect(Window &parent, const nall::string &path); + DialogWindow() = delete; + +private: + static nall::string fileOpen_(Window &parent, const nall::string &path, const nall::lstring& filter); + static nall::string fileSave_(Window &parent, const nall::string &path, const nall::lstring& filter); +}; + +struct MessageWindow { + enum class Buttons : unsigned { + Ok, + OkCancel, + YesNo, + }; + + enum class Response : unsigned { + Ok, + Cancel, + Yes, + No, + }; + + static Response information(Window &parent, const nall::string &text, Buttons = Buttons::Ok); + static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo); + static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok); + static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok); + MessageWindow() = delete; +}; + +struct Object { + Object(pObject &p); + Object& operator=(const Object&) = delete; + Object(const Object&) = delete; + virtual ~Object(); + pObject &p; +}; + +struct OS : Object { + static void main(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + OS(); + static void initialize(); +}; + +struct Timer : private nall::base_from_member, Object { + nall::function onTimeout; + + void setEnabled(bool enabled = true); + void setInterval(unsigned milliseconds); + + Timer(); + ~Timer(); + struct State; + State &state; + pTimer &p; +}; + +struct Window : private nall::base_from_member, Object { + nall::function onClose; + nall::function onKeyPress; + nall::function onKeyRelease; + nall::function onMove; + nall::function onSize; + + static Window& none(); + + inline void append() {} + inline void remove() {} + template void append(T &arg, Args&... args) { append_(arg); append(args...); } + template void remove(T &arg, Args&... args) { remove_(arg); remove(args...); } + + void append_(Layout &layout); + void append_(Menu &menu); + void append_(Widget &widget); + Color backgroundColor(); + Geometry frameGeometry(); + Geometry frameMargin(); + bool focused(); + bool fullScreen(); + Geometry geometry(); + void ignore(); + void remove_(Layout &layout); + void remove_(Menu &menu); + void remove_(Widget &widget); + void setBackgroundColor(const Color &color); + void setFrameGeometry(const Geometry &geometry); + void setFocused(); + void setFullScreen(bool fullScreen = true); + void setGeometry(const Geometry &geometry); + void setMenuFont(const nall::string &font); + void setMenuVisible(bool visible = true); + void setModal(bool modal = true); + void setResizable(bool resizable = true); + void setStatusFont(const nall::string &font); + void setStatusText(const nall::string &text); + void setStatusVisible(bool visible = true); + void setTitle(const nall::string &text); + void setVisible(bool visible = true); + void setWidgetFont(const nall::string &font); + nall::string statusText(); + void synchronizeLayout(); + bool visible(); + + Window(); + ~Window(); + struct State; + State &state; + pWindow &p; +}; + +struct Action : Object { + bool enabled(); + void setEnabled(bool enabled = true); + void setVisible(bool visible = true); + bool visible(); + + Action(pAction &p); + ~Action(); + struct State; + State &state; + pAction &p; +}; + +struct Menu : private nall::base_from_member, Action { + template void append(Args&... args) { append({args...}); } + template void remove(Args&... args) { remove({args...}); } + + void append(const nall::set &list); + void remove(const nall::set &list); + void setImage(const nall::image &image = nall::image{}); + void setText(const nall::string &text); + + Menu(); + ~Menu(); + struct State; + State &state; + pMenu &p; +}; + +struct Separator : private nall::base_from_member, Action { + Separator(); + ~Separator(); + pSeparator &p; +}; + +struct Item : private nall::base_from_member, Action { + nall::function onActivate; + + void setImage(const nall::image &image = nall::image{}); + void setText(const nall::string &text); + + Item(); + ~Item(); + struct State; + State &state; + pItem &p; +}; + +struct CheckItem : private nall::base_from_member, Action { + nall::function onToggle; + + bool checked(); + void setChecked(bool checked = true); + void setText(const nall::string &text); + + CheckItem(); + ~CheckItem(); + struct State; + State &state; + pCheckItem &p; +}; + +struct RadioItem : private nall::base_from_member, Action { + template static void group(Args&... args) { group({args...}); } + static void group(const nall::set &list); + + nall::function onActivate; + + bool checked(); + void setChecked(); + void setText(const nall::string &text); + nall::string text(); + + RadioItem(); + ~RadioItem(); + struct State; + State &state; + pRadioItem &p; +}; + +struct Sizable : Object { + virtual bool enabled() = 0; + Layout* layout(); + virtual Geometry minimumGeometry() = 0; + virtual void setEnabled(bool enabled = true) = 0; + virtual void setGeometry(const Geometry &geometry) = 0; + virtual void setVisible(bool visible = true) = 0; + virtual bool visible() = 0; + Window* window(); + + Sizable(pSizable &p); + ~Sizable(); + struct State; + State &state; + pSizable &p; +}; + +struct Layout : private nall::base_from_member, Sizable { + virtual void append(Sizable &sizable); + virtual void remove(Sizable &sizable); + virtual void reset() {} + virtual void synchronizeLayout() = 0; + + Layout(); + Layout(pLayout &p); + ~Layout(); + struct State; + State &state; + pLayout &p; +}; + +struct Widget : private nall::base_from_member, Sizable { + bool enabled(); + nall::string font(); + Geometry geometry(); + Geometry minimumGeometry(); + void setEnabled(bool enabled = true); + void setFocused(); + void setFont(const nall::string &font); + void setGeometry(const Geometry &geometry); + void setVisible(bool visible = true); + bool visible(); + + Widget(); + Widget(pWidget &p); + ~Widget(); + struct State; + State &state; + pWidget &p; +}; + +struct Button : private nall::base_from_member, Widget { + nall::function onActivate; + + void setImage(const nall::image &image = nall::image{}, Orientation = Orientation::Horizontal); + void setText(const nall::string &text); + + Button(); + ~Button(); + struct State; + State &state; + pButton &p; +}; + +struct Canvas : private nall::base_from_member, Widget { + nall::function onMouseLeave; + nall::function onMouseMove; + nall::function onMousePress; + nall::function onMouseRelease; + + uint32_t* data(); + bool setImage(const nall::image &image); + void setSize(const Size &size); + Size size(); + void update(); + + Canvas(); + ~Canvas(); + struct State; + State &state; + pCanvas &p; +}; + +struct CheckBox : private nall::base_from_member, Widget { + nall::function onToggle; + + bool checked(); + void setChecked(bool checked = true); + void setText(const nall::string &text); + + CheckBox(); + ~CheckBox(); + struct State; + State &state; + pCheckBox &p; +}; + +struct ComboBox : private nall::base_from_member, Widget { + nall::function onChange; + + template void append(const Args&... args) { append_({args...}); } + + void append_(const nall::lstring &list); + void modify(unsigned row, const nall::string &text); + void remove(unsigned row); + void reset(); + unsigned selection(); + void setSelection(unsigned row); + nall::string text(); + nall::string text(unsigned row); + + ComboBox(); + ~ComboBox(); + struct State; + State &state; + pComboBox &p; +}; + +struct HexEdit : private nall::base_from_member, Widget { + nall::function onRead; + nall::function onWrite; + + void setColumns(unsigned columns); + void setLength(unsigned length); + void setOffset(unsigned offset); + void setRows(unsigned rows); + void update(); + + HexEdit(); + ~HexEdit(); + struct State; + State &state; + pHexEdit &p; +}; + +struct HorizontalScrollBar : private nall::base_from_member, Widget { + nall::function onChange; + + unsigned length(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + HorizontalScrollBar(); + ~HorizontalScrollBar(); + struct State; + State &state; + pHorizontalScrollBar &p; +}; + +struct HorizontalSlider : private nall::base_from_member, Widget { + nall::function onChange; + + unsigned length(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + HorizontalSlider(); + ~HorizontalSlider(); + struct State; + State &state; + pHorizontalSlider &p; +}; + +struct Label : private nall::base_from_member, Widget { + void setText(const nall::string &text); + + Label(); + ~Label(); + struct State; + State &state; + pLabel &p; +}; + +struct LineEdit : private nall::base_from_member, Widget { + nall::function onActivate; + nall::function onChange; + + void setEditable(bool editable = true); + void setText(const nall::string &text); + nall::string text(); + + LineEdit(); + ~LineEdit(); + struct State; + State &state; + pLineEdit &p; +}; + +struct ListView : private nall::base_from_member, Widget { + nall::function onActivate; + nall::function onChange; + nall::function onToggle; + + template void append(const Args&... args) { append_({args...}); } + template void modify(unsigned row, const Args&... args) { modify_(row, {args...}); } + template void setHeaderText(const Args&... args) { setHeaderText_({args...}); } + + void append_(const nall::lstring &list); + void autoSizeColumns(); + bool checked(unsigned row); + void modify_(unsigned row, const nall::lstring &list); + void remove(unsigned row); + void reset(); + bool selected(); + unsigned selection(); + void setCheckable(bool checkable = true); + void setChecked(unsigned row, bool checked = true); + void setHeaderText_(const nall::lstring &list); + void setHeaderVisible(bool visible = true); + void setImage(unsigned row, unsigned column, const nall::image &image = nall::image{}); + void setSelected(bool selected = true); + void setSelection(unsigned row); + + ListView(); + ~ListView(); + struct State; + State &state; + pListView &p; +}; + +struct ProgressBar : private nall::base_from_member, Widget { + void setPosition(unsigned position); + + ProgressBar(); + ~ProgressBar(); + struct State; + State &state; + pProgressBar &p; +}; + +struct RadioBox : private nall::base_from_member, Widget { + template static void group(Args&... args) { group({args...}); } + static void group(const nall::set &list); + + nall::function onActivate; + + bool checked(); + void setChecked(); + void setText(const nall::string &text); + + RadioBox(); + ~RadioBox(); + struct State; + State &state; + pRadioBox &p; +}; + +struct TextEdit : private nall::base_from_member, Widget { + nall::function onChange; + + void setCursorPosition(unsigned position); + void setEditable(bool editable = true); + void setText(const nall::string &text); + void setWordWrap(bool wordWrap = true); + nall::string text(); + + TextEdit(); + ~TextEdit(); + struct State; + State &state; + pTextEdit &p; +}; + +struct VerticalScrollBar : private nall::base_from_member, Widget { + nall::function onChange; + + unsigned length(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + VerticalScrollBar(); + ~VerticalScrollBar(); + struct State; + State &state; + pVerticalScrollBar &p; +}; + +struct VerticalSlider : private nall::base_from_member, Widget { + nall::function onChange; + + unsigned length(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + VerticalSlider(); + ~VerticalSlider(); + struct State; + State &state; + pVerticalSlider &p; +}; + +struct Viewport : private nall::base_from_member, Widget { + nall::function onMouseLeave; + nall::function onMouseMove; + nall::function onMousePress; + nall::function onMouseRelease; + + uintptr_t handle(); + + Viewport(); + ~Viewport(); + pViewport &p; +}; + +#include "layout/fixed-layout.hpp" +#include "layout/horizontal-layout.hpp" +#include "layout/vertical-layout.hpp" diff --git a/kaijuu/phoenix/core/keyboard.hpp b/kaijuu/phoenix/core/keyboard.hpp new file mode 100644 index 00000000..ed04ec05 --- /dev/null +++ b/kaijuu/phoenix/core/keyboard.hpp @@ -0,0 +1,45 @@ +//each code refers to a physical key +//names are taken assuming: NumLock on, CapsLock off, Shift off +//layout uses US-104 keyboard +enum class Scancode : unsigned { + None, + + Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + PrintScreen, ScrollLock, Pause, + Insert, Delete, Home, End, PageUp, PageDown, + Up, Down, Left, Right, + + Grave, Number1, Number2, Number3, Number4, Number5, Number6, Number7, Number8, Number9, Number0, Minus, Equal, Backspace, + BracketLeft, BracketRight, Backslash, Semicolon, Apostrophe, Comma, Period, Slash, + Tab, CapsLock, Return, ShiftLeft, ShiftRight, ControlLeft, ControlRight, SuperLeft, SuperRight, AltLeft, AltRight, Space, Menu, + A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + + NumLock, Divide, Multiply, Subtract, Add, Enter, Point, + Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0, + + Limit, +}; + +//each enum refers to a translated scancode (eg Shift+1 = !) +enum class Keycode : unsigned { + None, + + Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + PrintScreen, SysRq, ScrollLock, Pause, Break, + Insert, Delete, Home, End, PageUp, PageDown, + Up, Down, Left, Right, + + Grave, Number1, Number2, Number3, Number4, Number5, Number6, Number7, Number8, Number9, Number0, Minus, Equal, Backspace, + Tilde, Exclamation, At, Pound, Dollar, Percent, Power, Ampersand, Asterisk, ParenthesisLeft, ParenthesisRight, Underscore, Plus, + BracketLeft, BracketRight, Backslash, Semicolon, Apostrophe, Comma, Period, Slash, + BraceLeft, BraceRight, Pipe, Colon, Quote, CaretLeft, CaretRight, Question, + Tab, CapsLock, Return, ShiftLeft, ShiftRight, ControlLeft, ControlRight, SuperLeft, SuperRight, AltLeft, AltRight, Space, Menu, + A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, + + NumLock, Divide, Multiply, Subtract, Add, Enter, Point, + Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0, + KeypadInsert, KeypadDelete, KeypadHome, KeypadEnd, KeypadPageUp, KeypadPageDown, KeypadUp, KeypadDown, KeypadLeft, KeypadRight, KeypadCenter, + + Limit, +}; diff --git a/kaijuu/phoenix/core/layout/fixed-layout.cpp b/kaijuu/phoenix/core/layout/fixed-layout.cpp new file mode 100644 index 00000000..71ff3dac --- /dev/null +++ b/kaijuu/phoenix/core/layout/fixed-layout.cpp @@ -0,0 +1,80 @@ +void FixedLayout::append(Sizable &sizable, const Geometry &geometry) { + children.append({ &sizable, geometry }); + synchronizeLayout(); + if(window()) window()->synchronizeLayout(); +} + +void FixedLayout::append(Sizable &sizable) { + for(auto &child : children) if(child.sizable == &sizable) return; + Layout::append(sizable); + if(window()) window()->synchronizeLayout(); +} + +bool FixedLayout::enabled() { + if(layout()) return state.enabled && layout()->enabled(); + return state.enabled; +} + +Geometry FixedLayout::minimumGeometry() { + unsigned width = MinimumSize, height = MinimumSize; + for(auto &child : children) { + width = max(width, child.sizable->minimumGeometry().width); + height = max(height, child.sizable->minimumGeometry().height); + } + return { 0, 0, width, height }; +} + +void FixedLayout::remove(Sizable &sizable) { + for(unsigned n = 0; n < children.size(); n++) { + if(children[n].sizable == &sizable) { + children.remove(n); + Layout::remove(sizable); + if(window()) window()->synchronizeLayout(); + break; + } + } +} + +void FixedLayout::reset() { + for(auto &child : children) { + if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); + } +} + +void FixedLayout::setEnabled(bool enabled) { + state.enabled = enabled; + for(auto &child : children) { + child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->enabled() : enabled); + } +} + +void FixedLayout::setGeometry(const Geometry &geometry) { +} + +void FixedLayout::setVisible(bool visible) { + state.visible = visible; + for(auto &child : children) { + child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->visible() : visible); + } +} + +void FixedLayout::synchronizeLayout() { + for(auto &child : children) { + Layout::append(*child.sizable); + child.sizable->setGeometry(child.geometry); + } +} + +bool FixedLayout::visible() { + if(layout()) return state.visible && layout()->visible(); + return state.visible; +} + +FixedLayout::FixedLayout() { + state.enabled = true; + state.visible = true; +} + +FixedLayout::~FixedLayout() { + while(children.size()) remove(*children[0].sizable); +} diff --git a/kaijuu/phoenix/core/layout/fixed-layout.hpp b/kaijuu/phoenix/core/layout/fixed-layout.hpp new file mode 100644 index 00000000..a67f2185 --- /dev/null +++ b/kaijuu/phoenix/core/layout/fixed-layout.hpp @@ -0,0 +1,27 @@ +struct FixedLayout : Layout { + void append(Sizable &sizable, const Geometry &geometry); + void append(Sizable &sizable); + bool enabled(); + Geometry minimumGeometry(); + void remove(Sizable &sizable); + void reset(); + void setEnabled(bool enabled = true); + void setGeometry(const Geometry &geometry); + void setVisible(bool visible = true); + void synchronizeLayout(); + bool visible(); + FixedLayout(); + ~FixedLayout(); + +//private: + struct State { + bool enabled; + bool visible; + } state; + + struct Children { + Sizable *sizable; + Geometry geometry; + }; + nall::vector children; +}; diff --git a/kaijuu/phoenix/core/layout/horizontal-layout.cpp b/kaijuu/phoenix/core/layout/horizontal-layout.cpp new file mode 100644 index 00000000..a1146038 --- /dev/null +++ b/kaijuu/phoenix/core/layout/horizontal-layout.cpp @@ -0,0 +1,142 @@ +void HorizontalLayout::append(Sizable &sizable, const Size &size, unsigned spacing) { + for(auto &child : children) if(child.sizable == &sizable) return; + children.append({ &sizable, size.width, size.height, spacing }); + synchronizeLayout(); + if(window()) window()->synchronizeLayout(); +} + +void HorizontalLayout::append(Sizable &sizable) { + for(auto &child : children) if(child.sizable == &sizable) return; + Layout::append(sizable); + if(window()) window()->synchronizeLayout(); +} + +bool HorizontalLayout::enabled() { + if(layout()) return state.enabled && layout()->enabled(); + return state.enabled; +} + +Geometry HorizontalLayout::minimumGeometry() { + unsigned width = 0, height = 0; + + for(auto &child : children) { + width += child.spacing; + if(child.width == MinimumSize || child.width == MaximumSize) { + width += child.sizable->minimumGeometry().width; + continue; + } + width += child.width; + } + + for(auto &child : children) { + if(child.height == MinimumSize || child.height == MaximumSize) { + height = max(height, child.sizable->minimumGeometry().height); + continue; + } + height = max(height, child.height); + } + + return { 0, 0, state.margin * 2 + width, state.margin * 2 + height }; +} + +void HorizontalLayout::remove(Sizable &sizable) { + for(unsigned n = 0; n < children.size(); n++) { + if(children[n].sizable == &sizable) { + if(dynamic_cast(children[n].sizable)) { + Layout *layout = (Layout*)children[n].sizable; + layout->reset(); + } + children.remove(n); + Layout::remove(sizable); + if(window()) window()->synchronizeLayout(); + break; + } + } +} + +void HorizontalLayout::reset() { + for(auto &child : children) { + if(window() && dynamic_cast(child.sizable)) ((Layout*)child.sizable)->reset(); + if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); + } +} + +void HorizontalLayout::setAlignment(double alignment) { + state.alignment = max(0.0, min(1.0, alignment)); +} + +void HorizontalLayout::setEnabled(bool enabled) { + state.enabled = enabled; + for(auto &child : children) { + child.sizable->setEnabled(dynamic_cast(child.sizable) ? child.sizable->enabled() : enabled); + } +} + +void HorizontalLayout::setGeometry(const Geometry &containerGeometry) { + auto children = this->children; + for(auto &child : children) { + if(child.width == MinimumSize) child.width = child.sizable->minimumGeometry().width; + if(child.height == MinimumSize) child.height = child.sizable->minimumGeometry().height; + } + + Geometry geometry = containerGeometry; + geometry.x += state.margin; + geometry.y += state.margin; + geometry.width -= state.margin * 2; + geometry.height -= state.margin * 2; + + unsigned minimumWidth = 0, maximumWidthCounter = 0; + for(auto &child : children) { + if(child.width == MaximumSize) maximumWidthCounter++; + if(child.width != MaximumSize) minimumWidth += child.width; + minimumWidth += child.spacing; + } + + for(auto &child : children) { + if(child.width == MaximumSize) child.width = (geometry.width - minimumWidth) / maximumWidthCounter; + if(child.height == MaximumSize) child.height = geometry.height; + } + + unsigned maximumHeight = 0; + for(auto &child : children) maximumHeight = max(maximumHeight, child.height); + + for(auto &child : children) { + unsigned pivot = (maximumHeight - child.height) * state.alignment; + Geometry childGeometry = { geometry.x, geometry.y + pivot, child.width, child.height }; + child.sizable->setGeometry(childGeometry); + + geometry.x += child.width + child.spacing; + geometry.width -= child.width + child.spacing; + } +} + +void HorizontalLayout::setMargin(unsigned margin) { + state.margin = margin; +} + +void HorizontalLayout::setVisible(bool visible) { + state.visible = visible; + for(auto &child : children) { + child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->visible() : visible); + } +} + +void HorizontalLayout::synchronizeLayout() { + for(auto &child : children) Layout::append(*child.sizable); +} + +bool HorizontalLayout::visible() { + if(layout()) return state.visible && layout()->visible(); + return state.visible; +} + +HorizontalLayout::HorizontalLayout() { + state.alignment = 0.5; + state.enabled = true; + state.margin = 0; + state.visible = true; +} + +HorizontalLayout::~HorizontalLayout() { + while(children.size()) remove(*children[0].sizable); +} diff --git a/kaijuu/phoenix/core/layout/horizontal-layout.hpp b/kaijuu/phoenix/core/layout/horizontal-layout.hpp new file mode 100644 index 00000000..96d4f101 --- /dev/null +++ b/kaijuu/phoenix/core/layout/horizontal-layout.hpp @@ -0,0 +1,31 @@ +struct HorizontalLayout : public Layout { + void append(Sizable &sizable, const Size &size, unsigned spacing = 0); + void append(Sizable &sizable); + bool enabled(); + Geometry minimumGeometry(); + void remove(Sizable &sizable); + void reset(); + void setAlignment(double alignment); + void setEnabled(bool enabled = true); + void setGeometry(const Geometry &geometry); + void setMargin(unsigned margin); + void setVisible(bool visible = true); + void synchronizeLayout(); + bool visible(); + HorizontalLayout(); + ~HorizontalLayout(); + +//private: + struct State { + double alignment; + bool enabled; + unsigned margin; + bool visible; + } state; + + struct Children { + Sizable *sizable; + unsigned width, height, spacing; + }; + nall::vector children; +}; diff --git a/kaijuu/phoenix/core/layout/vertical-layout.cpp b/kaijuu/phoenix/core/layout/vertical-layout.cpp new file mode 100644 index 00000000..4fd6315b --- /dev/null +++ b/kaijuu/phoenix/core/layout/vertical-layout.cpp @@ -0,0 +1,142 @@ +void VerticalLayout::append(Sizable &sizable, const Size &size, unsigned spacing) { + for(auto &child : children) if(child.sizable == &sizable) return; + children.append({ &sizable, size.width, size.height, spacing }); + synchronizeLayout(); + if(window()) window()->synchronizeLayout(); +} + +void VerticalLayout::append(Sizable &sizable) { + for(auto &child : children) if(child.sizable == &sizable) return; + Layout::append(sizable); + if(window()) window()->synchronizeLayout(); +} + +bool VerticalLayout::enabled() { + if(layout()) return state.enabled && layout()->enabled(); + return state.enabled; +} + +Geometry VerticalLayout::minimumGeometry() { + unsigned width = 0, height = 0; + + for(auto &child : children) { + if(child.width == MinimumSize || child.width == MaximumSize) { + width = max(width, child.sizable->minimumGeometry().width); + continue; + } + width = max(width, child.width); + } + + for(auto &child : children) { + height += child.spacing; + if(child.height == MinimumSize || child.height == MaximumSize) { + height += child.sizable->minimumGeometry().height; + continue; + } + height += child.height; + } + + return { 0, 0, state.margin * 2 + width, state.margin * 2 + height }; +} + +void VerticalLayout::remove(Sizable &sizable) { + for(unsigned n = 0; n < children.size(); n++) { + if(children[n].sizable == &sizable) { + if(dynamic_cast(children[n].sizable)) { + Layout *layout = (Layout*)children[n].sizable; + layout->reset(); + } + children.remove(n); + Layout::remove(sizable); + if(window()) window()->synchronizeLayout(); + break; + } + } +} + +void VerticalLayout::reset() { + for(auto &child : children) { + if(window() && dynamic_cast(child.sizable)) ((Layout*)child.sizable)->reset(); + if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); + } +} + +void VerticalLayout::setAlignment(double alignment) { + state.alignment = max(0.0, min(1.0, alignment)); +} + +void VerticalLayout::setEnabled(bool enabled) { + state.enabled = enabled; + for(auto &child : children) { + child.sizable->setEnabled(dynamic_cast(child.sizable) ? child.sizable->enabled() : enabled); + } +} + +void VerticalLayout::setGeometry(const Geometry &containerGeometry) { + auto children = this->children; + for(auto &child : children) { + if(child.width == MinimumSize) child.width = child.sizable->minimumGeometry().width; + if(child.height == MinimumSize) child.height = child.sizable->minimumGeometry().height; + } + + Geometry geometry = containerGeometry; + geometry.x += state.margin; + geometry.y += state.margin; + geometry.width -= state.margin * 2; + geometry.height -= state.margin * 2; + + unsigned minimumHeight = 0, maximumHeightCounter = 0; + for(auto &child : children) { + if(child.height == MaximumSize) maximumHeightCounter++; + if(child.height != MaximumSize) minimumHeight += child.height; + minimumHeight += child.spacing; + } + + for(auto &child : children) { + if(child.width == MaximumSize) child.width = geometry.width; + if(child.height == MaximumSize) child.height = (geometry.height - minimumHeight) / maximumHeightCounter; + } + + unsigned maximumWidth = 0; + for(auto &child : children) maximumWidth = max(maximumWidth, child.width); + + for(auto &child : children) { + unsigned pivot = (maximumWidth - child.width) * state.alignment; + Geometry childGeometry = { geometry.x + pivot, geometry.y, child.width, child.height }; + child.sizable->setGeometry(childGeometry); + + geometry.y += child.height + child.spacing; + geometry.height -= child.height + child.spacing; + } +} + +void VerticalLayout::setMargin(unsigned margin) { + state.margin = margin; +} + +void VerticalLayout::setVisible(bool visible) { + state.visible = visible; + for(auto &child : children) { + child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->visible() : visible); + } +} + +void VerticalLayout::synchronizeLayout() { + for(auto &child : children) Layout::append(*child.sizable); +} + +bool VerticalLayout::visible() { + if(layout()) return state.visible && layout()->visible(); + return state.visible; +} + +VerticalLayout::VerticalLayout() { + state.alignment = 0.0; + state.enabled = true; + state.margin = 0; + state.visible = true; +} + +VerticalLayout::~VerticalLayout() { + while(children.size()) remove(*children[0].sizable); +} diff --git a/kaijuu/phoenix/core/layout/vertical-layout.hpp b/kaijuu/phoenix/core/layout/vertical-layout.hpp new file mode 100644 index 00000000..8273dbe2 --- /dev/null +++ b/kaijuu/phoenix/core/layout/vertical-layout.hpp @@ -0,0 +1,31 @@ +struct VerticalLayout : public Layout { + void append(Sizable &sizable, const Size &size, unsigned spacing = 0); + void append(Sizable &sizable); + bool enabled(); + Geometry minimumGeometry(); + void remove(Sizable &sizable); + void reset(); + void setAlignment(double alignment); + void setEnabled(bool enabled = true); + void setGeometry(const Geometry &geometry); + void setMargin(unsigned margin); + void setVisible(bool visible = true); + void synchronizeLayout(); + bool visible(); + VerticalLayout(); + ~VerticalLayout(); + +//private: + struct State { + double alignment; + bool enabled; + unsigned margin; + bool visible; + } state; + + struct Children { + Sizable *sizable; + unsigned width, height, spacing; + }; + nall::vector children; +}; diff --git a/kaijuu/phoenix/core/state.hpp b/kaijuu/phoenix/core/state.hpp new file mode 100644 index 00000000..2d46ca2f --- /dev/null +++ b/kaijuu/phoenix/core/state.hpp @@ -0,0 +1,278 @@ +struct Timer::State { + bool enabled; + unsigned milliseconds; + + State() { + enabled = false; + milliseconds = 0; + } +}; + +struct Window::State { + bool backgroundColorOverride; + Color backgroundColor; + bool fullScreen; + Geometry geometry; + bool ignore; + set layout; + set menu; + string menuFont; + bool menuVisible; + bool modal; + bool resizable; + string statusFont; + string statusText; + bool statusVisible; + string title; + bool visible; + set widget; + string widgetFont; + + State() { + backgroundColorOverride = false; + backgroundColor = {0, 0, 0, 255}; + fullScreen = false; + geometry = {128, 128, 256, 256}; + ignore = false; + menuVisible = false; + modal = false; + resizable = true; + statusVisible = false; + visible = false; + } +}; + +struct Action::State { + bool enabled; + Menu *menu; + bool visible; + Window *window; + + State() { + enabled = true; + menu = 0; + visible = true; + window = 0; + } +}; + +struct Menu::State { + set action; + nall::image image; + string text; + + State() : image(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0) { + } +}; + +struct Item::State { + nall::image image; + string text; + + State() : image(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0) { + } +}; + +struct CheckItem::State { + bool checked; + string text; + + State() { + checked = false; + } +}; + +struct RadioItem::State { + bool checked; + set group; + string text; + + State() { + checked = true; + } +}; + +struct Sizable::State { + Layout *layout; + Window *window; + + State() { + layout = 0; + window = 0; + } +}; + +struct Layout::State { + State() { + } +}; + +struct Widget::State { + bool abstract; + bool enabled; + string font; + Geometry geometry; + bool visible; + + State() { + abstract = false; + enabled = true; + geometry = {0, 0, 0, 0}; + visible = true; + } +}; + +struct Button::State { + nall::image image; + Orientation orientation; + string text; + + State() : image(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0) { + } +}; + +struct Canvas::State { + uint32_t *data; + unsigned width; + unsigned height; + + State() { + data = nullptr; + width = 256; + height = 256; + } +}; + +struct CheckBox::State { + bool checked; + string text; + + State() { + checked = false; + } +}; + +struct ComboBox::State { + unsigned selection; + vector text; + + State() { + selection = 0; + } +}; + +struct HexEdit::State { + unsigned columns; + unsigned length; + unsigned offset; + unsigned rows; + + State() { + columns = 16; + length = 0; + offset = 0; + rows = 16; + } +}; + +struct HorizontalScrollBar::State { + unsigned length; + unsigned position; + + State() { + length = 101; + position = 0; + } +}; + +struct HorizontalSlider::State { + unsigned length; + unsigned position; + + State() { + length = 101; + position = 0; + } +}; + +struct Label::State { + string text; +}; + +struct LineEdit::State { + bool editable; + string text; + + State() { + editable = true; + } +}; + +struct ListView::State { + bool checkable; + vector checked; + lstring headerText; + bool headerVisible; + vector> image; + bool selected; + unsigned selection; + vector text; + + State() { + checkable = false; + headerVisible = false; + selected = false; + selection = 0; + } +}; + +struct ProgressBar::State { + unsigned position; + + State() { + position = 0; + } +}; + +struct RadioBox::State { + bool checked; + set group; + string text; + + State() { + checked = true; + } +}; + +struct TextEdit::State { + unsigned cursorPosition; + bool editable; + string text; + bool wordWrap; + + State() { + cursorPosition = 0; + editable = true; + wordWrap = true; + } +}; + +struct VerticalScrollBar::State { + unsigned length; + unsigned position; + + State() { + length = 101; + position = 0; + } +}; + +struct VerticalSlider::State { + unsigned length; + unsigned position; + + State() { + length = 101; + position = 0; + } +}; diff --git a/kaijuu/phoenix/gtk/action/action.cpp b/kaijuu/phoenix/gtk/action/action.cpp new file mode 100644 index 00000000..950259de --- /dev/null +++ b/kaijuu/phoenix/gtk/action/action.cpp @@ -0,0 +1,27 @@ +void pAction::setEnabled(bool enabled) { + gtk_widget_set_sensitive(widget, enabled); +} + +void pAction::setVisible(bool visible) { + gtk_widget_set_visible(widget, visible); +} + +void pAction::constructor() { +} + +void pAction::orphan() { +} + +//GTK+ uses _ for mnemonics, __ for _ +//transform so that & is used for mnemonics, && for & +string pAction::mnemonic(string text) { + text.transform("&_", "\x01\x02"); + text.replace("\x01\x01", "&"); + text.transform("\x01", "_"); + text.replace("\x02", "__"); + return text; +} + +void pAction::setFont(const string &font) { + pFont::setFont(widget, font); +} diff --git a/kaijuu/phoenix/gtk/action/check-item.cpp b/kaijuu/phoenix/gtk/action/check-item.cpp new file mode 100644 index 00000000..2cc182a6 --- /dev/null +++ b/kaijuu/phoenix/gtk/action/check-item.cpp @@ -0,0 +1,33 @@ +static void CheckItem_toggle(CheckItem *self) { + if(self->p.locked == false && self->onToggle) self->onToggle(); +} + +bool pCheckItem::checked() { + return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); +} + +void pCheckItem::setChecked(bool checked) { + locked = true; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), checked); + locked = false; +} + +void pCheckItem::setText(const string &text) { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), mnemonic(text)); +} + +void pCheckItem::constructor() { + widget = gtk_check_menu_item_new_with_mnemonic(""); + setChecked(checkItem.state.checked); + setText(checkItem.state.text); + g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(CheckItem_toggle), (gpointer)&checkItem); +} + +void pCheckItem::destructor() { + gtk_widget_destroy(widget); +} + +void pCheckItem::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/action/item.cpp b/kaijuu/phoenix/gtk/action/item.cpp new file mode 100644 index 00000000..afab955e --- /dev/null +++ b/kaijuu/phoenix/gtk/action/item.cpp @@ -0,0 +1,31 @@ +static void Item_activate(Item *self) { + if(self->onActivate) self->onActivate(); +} + +void pItem::setImage(const image &image) { + if(image.empty() == false) { + GtkImage *gtkImage = CreateImage(image, true); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); + } else { + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), nullptr); + } +} + +void pItem::setText(const string &text) { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), mnemonic(text)); +} + +void pItem::constructor() { + widget = gtk_image_menu_item_new_with_mnemonic(""); + g_signal_connect_swapped(G_OBJECT(widget), "activate", G_CALLBACK(Item_activate), (gpointer)&item); + setText(item.state.text); +} + +void pItem::destructor() { + gtk_widget_destroy(widget); +} + +void pItem::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/action/menu.cpp b/kaijuu/phoenix/gtk/action/menu.cpp new file mode 100644 index 00000000..92252085 --- /dev/null +++ b/kaijuu/phoenix/gtk/action/menu.cpp @@ -0,0 +1,51 @@ +void pMenu::append(Action &action) { + action.state.window = this->action.state.window; + + gtk_menu_shell_append(GTK_MENU_SHELL(gtkMenu), action.p.widget); + if(action.state.window && action.state.window->state.menuFont != "") { + action.p.setFont(action.state.window->state.menuFont); + } + gtk_widget_show(action.p.widget); +} + +void pMenu::remove(Action &action) { + action.p.orphan(); + action.state.window = 0; +} + +void pMenu::setImage(const image &image) { + if(image.empty() == false) { + GtkImage *gtkImage = CreateImage(image, true); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); + } else { + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), nullptr); + } +} + +void pMenu::setText(const string &text) { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), mnemonic(text)); +} + +void pMenu::constructor() { + gtkMenu = gtk_menu_new(); + widget = gtk_image_menu_item_new_with_mnemonic(""); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(widget), gtkMenu); + setText(menu.state.text); +} + +void pMenu::destructor() { + gtk_widget_destroy(gtkMenu); + gtk_widget_destroy(widget); +} + +void pMenu::orphan() { + for(auto &action : menu.state.action) action.p.orphan(); + destructor(); + constructor(); + for(auto &action : menu.state.action) append(action); +} + +void pMenu::setFont(const string &font) { + pAction::setFont(font); + for(auto &item : menu.state.action) item.p.setFont(font); +} diff --git a/kaijuu/phoenix/gtk/action/radio-item.cpp b/kaijuu/phoenix/gtk/action/radio-item.cpp new file mode 100644 index 00000000..a599d70b --- /dev/null +++ b/kaijuu/phoenix/gtk/action/radio-item.cpp @@ -0,0 +1,48 @@ +static void RadioItem_activate(RadioItem *self) { + for(auto &item : self->state.group) item.state.checked = (&item == self); + if(self->p.locked == false && self->checked() && self->onActivate) self->onActivate(); +} + +bool pRadioItem::checked() { + return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); +} + +void pRadioItem::setChecked() { + locked = true; + for(auto &item : radioItem.state.group) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item.p.widget), false); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), true); + locked = false; +} + +void pRadioItem::setGroup(const set &group) { + for(unsigned n = 0; n < group.size(); n++) { + if(n == 0) continue; + GSList *currentGroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(group[0].p.widget)); + if(currentGroup != gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(group[n].p.widget))) { + gtk_radio_menu_item_set_group(GTK_RADIO_MENU_ITEM(group[n].p.widget), currentGroup); + } + } +} + +void pRadioItem::setText(const string &text) { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), mnemonic(text)); +} + +void pRadioItem::constructor() { + widget = gtk_radio_menu_item_new_with_mnemonic(0, ""); + setGroup(radioItem.state.group); + setText(radioItem.state.text); + for(auto &item : radioItem.state.group) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item.p.widget), item.state.checked); + } + g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(RadioItem_activate), (gpointer)&radioItem); +} + +void pRadioItem::destructor() { + gtk_widget_destroy(widget); +} + +void pRadioItem::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/action/separator.cpp b/kaijuu/phoenix/gtk/action/separator.cpp new file mode 100644 index 00000000..8b7a1a6b --- /dev/null +++ b/kaijuu/phoenix/gtk/action/separator.cpp @@ -0,0 +1,12 @@ +void pSeparator::constructor() { + widget = gtk_separator_menu_item_new(); +} + +void pSeparator::destructor() { + gtk_widget_destroy(widget); +} + +void pSeparator::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/desktop.cpp b/kaijuu/phoenix/gtk/desktop.cpp new file mode 100644 index 00000000..2b1801ad --- /dev/null +++ b/kaijuu/phoenix/gtk/desktop.cpp @@ -0,0 +1,36 @@ +Size pDesktop::size() { + return { + gdk_screen_get_width(gdk_screen_get_default()), + gdk_screen_get_height(gdk_screen_get_default()) + }; +} + +Geometry pDesktop::workspace() { + XlibDisplay *display = XOpenDisplay(0); + int screen = DefaultScreen(display); + + static Atom atom = XlibNone; + if(atom == XlibNone) atom = XInternAtom(display, "_NET_WORKAREA", True); + + int format; + unsigned char *data = 0; + unsigned long items, after; + Atom returnAtom; + + int result = XGetWindowProperty( + display, RootWindow(display, screen), atom, 0, 4, False, XA_CARDINAL, &returnAtom, &format, &items, &after, &data + ); + + XCloseDisplay(display); + + if(result == Success && returnAtom == XA_CARDINAL && format == 32 && items == 4) { + unsigned long *workarea = (unsigned long*)data; + return { (signed)workarea[0], (signed)workarea[1], (unsigned)workarea[2], (unsigned)workarea[3] }; + } + + return { + 0, 0, + gdk_screen_get_width(gdk_screen_get_default()), + gdk_screen_get_height(gdk_screen_get_default()) + }; +} diff --git a/kaijuu/phoenix/gtk/dialog-window.cpp b/kaijuu/phoenix/gtk/dialog-window.cpp new file mode 100644 index 00000000..eb04bd64 --- /dev/null +++ b/kaijuu/phoenix/gtk/dialog-window.cpp @@ -0,0 +1,69 @@ +static string FileDialog(bool save, Window &parent, const string &path, const lstring &filter) { + string name; + + GtkWidget *dialog = gtk_file_chooser_dialog_new( + save == 0 ? "Load File" : "Save File", + &parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr, + save == 0 ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + (const gchar*)nullptr + ); + + if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); + + for(auto &filterItem : filter) { + GtkFileFilter *gtkFilter = gtk_file_filter_new(); + gtk_file_filter_set_name(gtkFilter, filterItem); + lstring part; + part.split("(", filterItem); + part[1].rtrim<1>(")"); + lstring list; + list.split(",", part[1]); + for(auto &pattern : list) gtk_file_filter_add_pattern(gtkFilter, pattern); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), gtkFilter); + } + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + name = temp; + g_free(temp); + } + + gtk_widget_destroy(dialog); + return name; +} + +string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) { + return FileDialog(0, parent, path, filter); +} + +string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) { + return FileDialog(1, parent, path, filter); +} + +string pDialogWindow::folderSelect(Window &parent, const string &path) { + string name; + + GtkWidget *dialog = gtk_file_chooser_dialog_new( + "Select Folder", + &parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr, + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + (const gchar*)nullptr + ); + + if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + name = temp; + g_free(temp); + } + + gtk_widget_destroy(dialog); + if(name == "") return ""; + if(name.endswith("/") == false) name.append("/"); + return name; +} diff --git a/kaijuu/phoenix/gtk/font.cpp b/kaijuu/phoenix/gtk/font.cpp new file mode 100644 index 00000000..cb6889d1 --- /dev/null +++ b/kaijuu/phoenix/gtk/font.cpp @@ -0,0 +1,58 @@ +Geometry pFont::geometry(const string &description, const string &text) { + PangoFontDescription *font = create(description); + Geometry geometry = pFont::geometry(font, text); + free(font); + return geometry; +} + +PangoFontDescription* pFont::create(const string &description) { + lstring part; + part.split(",", description); + for(auto &item : part) item.trim(" "); + + string family = "Sans"; + unsigned size = 8u; + bool bold = false; + bool italic = false; + + if(part[0] != "") family = part[0]; + if(part.size() >= 2) size = decimal(part[1]); + if(part.size() >= 3) bold = part[2].position("Bold"); + if(part.size() >= 3) italic = part[2].position("Italic"); + + PangoFontDescription *font = pango_font_description_new(); + pango_font_description_set_family(font, family); + pango_font_description_set_size(font, size * PANGO_SCALE); + pango_font_description_set_weight(font, !bold ? PANGO_WEIGHT_NORMAL : PANGO_WEIGHT_BOLD); + pango_font_description_set_style(font, !italic ? PANGO_STYLE_NORMAL : PANGO_STYLE_OBLIQUE); + return font; +} + +void pFont::free(PangoFontDescription *font) { + pango_font_description_free(font); +} + +Geometry pFont::geometry(PangoFontDescription *font, const string &text) { + PangoContext *context = gdk_pango_context_get_for_screen(gdk_screen_get_default()); + PangoLayout *layout = pango_layout_new(context); + pango_layout_set_font_description(layout, font); + pango_layout_set_text(layout, text, -1); + int width = 0, height = 0; + pango_layout_get_pixel_size(layout, &width, &height); + g_object_unref((gpointer)layout); + return { 0, 0, width, height }; +} + +void pFont::setFont(GtkWidget *widget, const string &font) { + auto gtkFont = pFont::create(font); + pFont::setFont(widget, (gpointer)gtkFont); + pFont::free(gtkFont); +} + +void pFont::setFont(GtkWidget *widget, gpointer font) { + if(font == 0) return; + gtk_widget_modify_font(widget, (PangoFontDescription*)font); + if(GTK_IS_CONTAINER(widget)) { + gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)pFont::setFont, font); + } +} diff --git a/kaijuu/phoenix/gtk/keyboard.cpp b/kaijuu/phoenix/gtk/keyboard.cpp new file mode 100644 index 00000000..5b346406 --- /dev/null +++ b/kaijuu/phoenix/gtk/keyboard.cpp @@ -0,0 +1,142 @@ +void pKeyboard::initialize() { + auto append = [](Keyboard::Scancode scancode, unsigned keysym) { + settings->keymap.insert(scancode, XKeysymToKeycode(pOS::display, keysym)); + }; + + append(Keyboard::Scancode::Escape, XK_Escape); + append(Keyboard::Scancode::F1, XK_F1); + append(Keyboard::Scancode::F2, XK_F2); + append(Keyboard::Scancode::F3, XK_F3); + append(Keyboard::Scancode::F4, XK_F4); + append(Keyboard::Scancode::F5, XK_F5); + append(Keyboard::Scancode::F6, XK_F6); + append(Keyboard::Scancode::F7, XK_F7); + append(Keyboard::Scancode::F8, XK_F8); + append(Keyboard::Scancode::F9, XK_F9); + append(Keyboard::Scancode::F10, XK_F10); + append(Keyboard::Scancode::F11, XK_F11); + append(Keyboard::Scancode::F12, XK_F12); + + append(Keyboard::Scancode::PrintScreen, XK_Print); + append(Keyboard::Scancode::ScrollLock, XK_Scroll_Lock); + append(Keyboard::Scancode::Pause, XK_Pause); + + append(Keyboard::Scancode::Insert, XK_Insert); + append(Keyboard::Scancode::Delete, XK_Delete); + append(Keyboard::Scancode::Home, XK_Home); + append(Keyboard::Scancode::End, XK_End); + append(Keyboard::Scancode::PageUp, XK_Prior); + append(Keyboard::Scancode::PageDown, XK_Next); + + append(Keyboard::Scancode::Up, XK_Up); + append(Keyboard::Scancode::Down, XK_Down); + append(Keyboard::Scancode::Left, XK_Left); + append(Keyboard::Scancode::Right, XK_Right); + + append(Keyboard::Scancode::Grave, XK_asciitilde); + append(Keyboard::Scancode::Number1, XK_1); + append(Keyboard::Scancode::Number2, XK_2); + append(Keyboard::Scancode::Number3, XK_3); + append(Keyboard::Scancode::Number4, XK_4); + append(Keyboard::Scancode::Number5, XK_5); + append(Keyboard::Scancode::Number6, XK_6); + append(Keyboard::Scancode::Number7, XK_7); + append(Keyboard::Scancode::Number8, XK_8); + append(Keyboard::Scancode::Number9, XK_9); + append(Keyboard::Scancode::Number0, XK_0); + append(Keyboard::Scancode::Minus, XK_minus); + append(Keyboard::Scancode::Equal, XK_equal); + append(Keyboard::Scancode::Backspace, XK_BackSpace); + + append(Keyboard::Scancode::BracketLeft, XK_bracketleft); + append(Keyboard::Scancode::BracketRight, XK_bracketright); + append(Keyboard::Scancode::Backslash, XK_backslash); + append(Keyboard::Scancode::Semicolon, XK_semicolon); + append(Keyboard::Scancode::Apostrophe, XK_apostrophe); + append(Keyboard::Scancode::Comma, XK_comma); + append(Keyboard::Scancode::Period, XK_period); + append(Keyboard::Scancode::Slash, XK_slash); + + append(Keyboard::Scancode::Tab, XK_Tab); + append(Keyboard::Scancode::CapsLock, XK_Caps_Lock); + append(Keyboard::Scancode::Return, XK_Return); + append(Keyboard::Scancode::ShiftLeft, XK_Shift_L); + append(Keyboard::Scancode::ShiftRight, XK_Shift_R); + append(Keyboard::Scancode::ControlLeft, XK_Control_L); + append(Keyboard::Scancode::ControlRight, XK_Control_R); + append(Keyboard::Scancode::SuperLeft, XK_Super_L); + append(Keyboard::Scancode::SuperRight, XK_Super_R); + append(Keyboard::Scancode::AltLeft, XK_Alt_L); + append(Keyboard::Scancode::AltRight, XK_Alt_R); + append(Keyboard::Scancode::Space, XK_space); + append(Keyboard::Scancode::Menu, XK_Menu); + + append(Keyboard::Scancode::A, XK_A); + append(Keyboard::Scancode::B, XK_B); + append(Keyboard::Scancode::C, XK_C); + append(Keyboard::Scancode::D, XK_D); + append(Keyboard::Scancode::E, XK_E); + append(Keyboard::Scancode::F, XK_F); + append(Keyboard::Scancode::G, XK_G); + append(Keyboard::Scancode::H, XK_H); + append(Keyboard::Scancode::I, XK_I); + append(Keyboard::Scancode::J, XK_J); + append(Keyboard::Scancode::K, XK_K); + append(Keyboard::Scancode::L, XK_L); + append(Keyboard::Scancode::M, XK_M); + append(Keyboard::Scancode::N, XK_N); + append(Keyboard::Scancode::O, XK_O); + append(Keyboard::Scancode::P, XK_P); + append(Keyboard::Scancode::Q, XK_Q); + append(Keyboard::Scancode::R, XK_R); + append(Keyboard::Scancode::S, XK_S); + append(Keyboard::Scancode::T, XK_T); + append(Keyboard::Scancode::U, XK_U); + append(Keyboard::Scancode::V, XK_V); + append(Keyboard::Scancode::W, XK_W); + append(Keyboard::Scancode::X, XK_X); + append(Keyboard::Scancode::Y, XK_Y); + append(Keyboard::Scancode::Z, XK_Z); + + append(Keyboard::Scancode::NumLock, XK_Num_Lock); + append(Keyboard::Scancode::Divide, XK_KP_Divide); + append(Keyboard::Scancode::Multiply, XK_KP_Multiply); + append(Keyboard::Scancode::Subtract, XK_KP_Subtract); + append(Keyboard::Scancode::Add, XK_KP_Add); + append(Keyboard::Scancode::Enter, XK_KP_Enter); + append(Keyboard::Scancode::Point, XK_KP_Decimal); + + append(Keyboard::Scancode::Keypad1, XK_KP_1); + append(Keyboard::Scancode::Keypad2, XK_KP_2); + append(Keyboard::Scancode::Keypad3, XK_KP_3); + append(Keyboard::Scancode::Keypad4, XK_KP_4); + append(Keyboard::Scancode::Keypad5, XK_KP_5); + append(Keyboard::Scancode::Keypad6, XK_KP_6); + append(Keyboard::Scancode::Keypad7, XK_KP_7); + append(Keyboard::Scancode::Keypad8, XK_KP_8); + append(Keyboard::Scancode::Keypad9, XK_KP_9); + append(Keyboard::Scancode::Keypad0, XK_KP_0); +} + +bool pKeyboard::pressed(Keyboard::Scancode scancode) { + char state[256]; + XQueryKeymap(pOS::display, state); + unsigned id = settings->keymap.lhs[scancode]; + return state[id >> 3] & (1 << (id & 7)); +} + +vector pKeyboard::state() { + vector output; + output.resize((unsigned)Keyboard::Scancode::Limit); + for(auto &n : output) n = false; + + char state[256]; + XQueryKeymap(pOS::display, state); + for(auto &n : settings->keymap.rhs) { + if(state[n.name >> 3] & (1 << (n.name & 7))) { + output[(unsigned)n.data] = true; + } + } + + return output; +} diff --git a/kaijuu/phoenix/gtk/message-window.cpp b/kaijuu/phoenix/gtk/message-window.cpp new file mode 100644 index 00000000..7cd2172a --- /dev/null +++ b/kaijuu/phoenix/gtk/message-window.cpp @@ -0,0 +1,61 @@ +static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, gint response) { + if(response == GTK_RESPONSE_OK) return MessageWindow::Response::Ok; + if(response == GTK_RESPONSE_CANCEL) return MessageWindow::Response::Cancel; + if(response == GTK_RESPONSE_YES) return MessageWindow::Response::Yes; + if(response == GTK_RESPONSE_NO) return MessageWindow::Response::No; + if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel; + if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { + GtkButtonsType buttonsType = GTK_BUTTONS_OK; + if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL; + if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO; + GtkWidget *dialog = gtk_message_dialog_new( + &parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr, + GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, buttonsType, "%s", (const char*)text + ); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return MessageWindow_response(buttons, response); +} + +MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { + GtkButtonsType buttonsType = GTK_BUTTONS_OK; + if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL; + if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO; + GtkWidget *dialog = gtk_message_dialog_new( + &parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr, + GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, buttonsType, "%s", (const char*)text + ); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return MessageWindow_response(buttons, response); +} + +MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { + GtkButtonsType buttonsType = GTK_BUTTONS_OK; + if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL; + if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO; + GtkWidget *dialog = gtk_message_dialog_new( + &parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr, + GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, buttonsType, "%s", (const char*)text + ); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return MessageWindow_response(buttons, response); +} + +MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { + GtkButtonsType buttonsType = GTK_BUTTONS_OK; + if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL; + if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO; + GtkWidget *dialog = gtk_message_dialog_new( + &parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr, + GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, buttonsType, "%s", (const char*)text + ); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return MessageWindow_response(buttons, response); +} diff --git a/kaijuu/phoenix/gtk/mouse.cpp b/kaijuu/phoenix/gtk/mouse.cpp new file mode 100644 index 00000000..e00f7ff7 --- /dev/null +++ b/kaijuu/phoenix/gtk/mouse.cpp @@ -0,0 +1,20 @@ +Position pMouse::position() { + XlibWindow root, child; + int rootx, rooty, winx, winy; + unsigned int mask; + XQueryPointer(pOS::display, DefaultRootWindow(pOS::display), &root, &child, &rootx, &rooty, &winx, &winy, &mask); + return { rootx, rooty }; +} + +bool pMouse::pressed(Mouse::Button button) { + XlibWindow root, child; + int rootx, rooty, winx, winy; + unsigned int mask; + XQueryPointer(pOS::display, DefaultRootWindow(pOS::display), &root, &child, &rootx, &rooty, &winx, &winy, &mask); + switch(button) { + case Mouse::Button::Left: return mask & Button1Mask; + case Mouse::Button::Middle: return mask & Button2Mask; + case Mouse::Button::Right: return mask & Button3Mask; + } + return false; +} diff --git a/kaijuu/phoenix/gtk/platform.cpp b/kaijuu/phoenix/gtk/platform.cpp new file mode 100644 index 00000000..c6650dbb --- /dev/null +++ b/kaijuu/phoenix/gtk/platform.cpp @@ -0,0 +1,87 @@ +#include "platform.hpp" +#include "utility.cpp" +#include "settings.cpp" + +#include "desktop.cpp" +#include "keyboard.cpp" +#include "mouse.cpp" +#include "dialog-window.cpp" +#include "message-window.cpp" + +#include "font.cpp" +#include "timer.cpp" +#include "window.cpp" + +#include "action/action.cpp" +#include "action/menu.cpp" +#include "action/separator.cpp" +#include "action/item.cpp" +#include "action/check-item.cpp" +#include "action/radio-item.cpp" + +#include "widget/widget.cpp" +#include "widget/button.cpp" +#include "widget/canvas.cpp" +#include "widget/check-box.cpp" +#include "widget/combo-box.cpp" +#include "widget/hex-edit.cpp" +#include "widget/horizontal-scroll-bar.cpp" +#include "widget/horizontal-slider.cpp" +#include "widget/label.cpp" +#include "widget/line-edit.cpp" +#include "widget/list-view.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-box.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +XlibDisplay* pOS::display = 0; +Font pOS::defaultFont; + +void pOS::main() { + gtk_main(); +} + +bool pOS::pendingEvents() { + return gtk_events_pending(); +} + +void pOS::processEvents() { + while(pendingEvents()) gtk_main_iteration_do(false); +} + +void pOS::quit() { + gtk_main_quit(); +} + +void pOS::initialize() { + display = XOpenDisplay(0); + + settings = new Settings; + settings->load(); + + int argc = 1; + char *argv[2]; + argv[0] = new char[8]; + argv[1] = 0; + strcpy(argv[0], "phoenix"); + char **argvp = argv; + gtk_init(&argc, &argvp); + + gtk_rc_parse_string(R"( + style "phoenix-gtk" + { + GtkWindow::resize-grip-width = 0 + GtkWindow::resize-grip-height = 0 + GtkTreeView::vertical-separator = 0 + GtkComboBox::appears-as-list = 1 + } + class "GtkWindow" style "phoenix-gtk" + class "GtkTreeView" style "phoenix-gtk" + # class "GtkComboBox" style "phoenix-gtk" + )"); + + pKeyboard::initialize(); +} diff --git a/kaijuu/phoenix/gtk/platform.hpp b/kaijuu/phoenix/gtk/platform.hpp new file mode 100644 index 00000000..344e8239 --- /dev/null +++ b/kaijuu/phoenix/gtk/platform.hpp @@ -0,0 +1,501 @@ +struct Settings : public configuration { + bidirectional_map keymap; + + unsigned frameGeometryX; + unsigned frameGeometryY; + unsigned frameGeometryWidth; + unsigned frameGeometryHeight; + unsigned menuGeometryHeight; + unsigned statusGeometryHeight; + unsigned windowBackgroundColor; + + void load(); + void save(); + Settings(); +}; + +struct pWindow; +struct pMenu; +struct pLayout; +struct pWidget; + +struct pFont { + static Geometry geometry(const string &description, const string &text); + + static PangoFontDescription* create(const string &description); + static void free(PangoFontDescription *font); + static Geometry geometry(PangoFontDescription *font, const string &text); + static void setFont(GtkWidget *widget, const string &font); + static void setFont(GtkWidget *widget, gpointer font); +}; + +struct pDesktop { + static Size size(); + static Geometry workspace(); +}; + +struct pKeyboard { + static bool pressed(Keyboard::Scancode scancode); + static vector state(); + + static void initialize(); +}; + +struct pMouse { + static Position position(); + static bool pressed(Mouse::Button button); +}; + +struct pDialogWindow { + static string fileOpen(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); +}; + +struct pMessageWindow { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + +struct pObject { + Object &object; + bool locked; + + pObject(Object &object) : object(object), locked(false) {} + virtual ~pObject() {} + + void constructor() {} + void destructor() {} +}; + +struct pOS : public pObject { + static XlibDisplay *display; + static Font defaultFont; + + static void main(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + static void initialize(); +}; + +struct pTimer : public pObject { + Timer &timer; + + void setEnabled(bool enabled); + void setInterval(unsigned milliseconds); + + pTimer(Timer &timer) : pObject(timer), timer(timer) {} + void constructor(); +}; + +struct pWindow : public pObject { + Window &window; + GtkWidget *widget; + GtkWidget *menuContainer; + GtkWidget *formContainer; + GtkWidget *statusContainer; + GtkWidget *menu; + GtkWidget *status; + GtkAllocation lastAllocation; + bool onSizePending; + + static Window& none(); + + void append(Layout &layout); + void append(Menu &menu); + void append(Widget &widget); + Color backgroundColor(); + bool focused(); + Geometry frameMargin(); + Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); + void setBackgroundColor(const Color &color); + void setFocused(); + void setFullScreen(bool fullScreen); + void setGeometry(const Geometry &geometry); + void setMenuFont(const string &font); + void setMenuVisible(bool visible); + void setModal(bool modal); + void setResizable(bool resizable); + void setStatusFont(const string &font); + void setStatusText(const string &text); + void setStatusVisible(bool visible); + void setTitle(const string &text); + void setVisible(bool visible); + void setWidgetFont(const string &font); + + pWindow(Window &window) : pObject(window), window(window) {} + void constructor(); + unsigned menuHeight(); + unsigned statusHeight(); +}; + +struct pAction : public pObject { + Action &action; + GtkWidget *widget; + + void setEnabled(bool enabled); + void setVisible(bool visible); + + pAction(Action &action) : pObject(action), action(action) {} + void constructor(); + virtual void orphan(); + string mnemonic(string text); + virtual void setFont(const string &font); +}; + +struct pMenu : public pAction { + Menu &menu; + GtkWidget *gtkMenu; + + void append(Action &action); + void remove(Action &action); + void setImage(const image &image); + void setText(const string &text); + + pMenu(Menu &menu) : pAction(menu), menu(menu) {} + void constructor(); + void destructor(); + void orphan(); + void setFont(const string &font); +}; + +struct pSeparator : public pAction { + Separator &separator; + + pSeparator(Separator &separator) : pAction(separator), separator(separator) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pItem : public pAction { + Item &item; + + void setImage(const image &image); + void setText(const string &text); + + pItem(Item &item) : pAction(item), item(item) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pCheckItem : public pAction { + CheckItem &checkItem; + + bool checked(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pRadioItem : public pAction { + RadioItem &radioItem; + + bool checked(); + void setChecked(); + void setGroup(const set &group); + void setText(const string &text); + + pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} +}; + +struct pWidget : public pSizable { + Widget &widget; + GtkWidget *gtkWidget; + + bool enabled(); + virtual Geometry minimumGeometry(); + void setEnabled(bool enabled); + virtual void setFocused(); + virtual void setFont(const string &font); + virtual void setGeometry(const Geometry &geometry); + void setVisible(bool visible); + + pWidget(Widget &widget) : pSizable(widget), widget(widget) {} + void constructor(); + void destructor(); + virtual void orphan(); +}; + +struct pButton : public pWidget { + Button &button; + + Geometry minimumGeometry(); + void setImage(const image &image, Orientation orientation); + void setText(const string &text); + + pButton(Button &button) : pWidget(button), button(button) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pCanvas : public pWidget { + Canvas &canvas; + cairo_surface_t *surface; + + void setSize(const Size &size); + void update(); + + pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pCheckBox : public pWidget { + CheckBox &checkBox; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckBox(CheckBox &checkBox) : pWidget(checkBox), checkBox(checkBox) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pComboBox : public pWidget { + ComboBox &comboBox; + unsigned itemCounter; + + void append(const string &text); + void modify(unsigned row, const string &text); + void remove(unsigned row); + Geometry minimumGeometry(); + void reset(); + unsigned selection(); + void setSelection(unsigned row); + + pComboBox(ComboBox &comboBox) : pWidget(comboBox), comboBox(comboBox) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pHexEdit : public pWidget { + HexEdit &hexEdit; + GtkWidget *container; + GtkWidget *subWidget; + GtkWidget *scrollBar; + GtkTextBuffer *textBuffer; + GtkTextMark *textCursor; + + void setColumns(unsigned columns); + void setLength(unsigned length); + void setOffset(unsigned offset); + void setRows(unsigned rows); + void update(); + + pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} + void constructor(); + void destructor(); + void orphan(); + unsigned cursorPosition(); + bool keyPress(unsigned scancode); + void scroll(unsigned position); + void setCursorPosition(unsigned position); + void setScroll(); + void updateScroll(); +}; + +struct pHorizontalScrollBar : public pWidget { + HorizontalScrollBar &horizontalScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pHorizontalSlider : public pWidget { + HorizontalSlider &horizontalSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalSlider(HorizontalSlider &horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pLabel : public pWidget { + Label &label; + + Geometry minimumGeometry(); + void setText(const string &text); + + pLabel(Label &label) : pWidget(label), label(label) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pLineEdit : public pWidget { + LineEdit &lineEdit; + + Geometry minimumGeometry(); + void setEditable(bool editable); + void setText(const string &text); + string text(); + + pLineEdit(LineEdit &lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pListView : public pWidget { + ListView &listView; + GtkWidget *subWidget; + GtkListStore *store; + struct GtkColumn { + GtkTreeViewColumn *column; + GtkCellRenderer *checkbox, *icon, *text; + GtkWidget *label; + }; + vector column; + + void append(const lstring &text); + void autoSizeColumns(); + bool checked(unsigned row); + void modify(unsigned row, const lstring &text); + void remove(unsigned row); + void reset(); + bool selected(); + unsigned selection(); + void setCheckable(bool checkable); + void setChecked(unsigned row, bool checked); + void setHeaderText(const lstring &text); + void setHeaderVisible(bool visible); + void setImage(unsigned row, unsigned column, const nall::image &image); + void setSelected(bool selected); + void setSelection(unsigned row); + + pListView(ListView &listView) : pWidget(listView), listView(listView) {} + void constructor(); + void destructor(); + void orphan(); + void setFocused(); + void setFont(const string &font); +}; + +struct pProgressBar : public pWidget { + ProgressBar &progressBar; + + Geometry minimumGeometry(); + void setPosition(unsigned position); + + pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pRadioBox : public pWidget { + RadioBox &radioBox; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(); + void setGroup(const set &group); + void setText(const string &text); + + pRadioBox(RadioBox &radioBox) : pWidget(radioBox), radioBox(radioBox) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pTextEdit : public pWidget { + TextEdit &textEdit; + GtkWidget *subWidget; + GtkTextBuffer *textBuffer; + + void setCursorPosition(unsigned position); + void setEditable(bool editable); + void setText(const string &text); + void setWordWrap(bool wordWrap); + string text(); + + pTextEdit(TextEdit &textEdit) : pWidget(textEdit), textEdit(textEdit) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pVerticalScrollBar : public pWidget { + VerticalScrollBar &verticalScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pVerticalSlider : public pWidget { + VerticalSlider &verticalSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalSlider(VerticalSlider &verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pViewport : public pWidget { + Viewport &viewport; + + uintptr_t handle(); + + pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} + void constructor(); + void destructor(); + void orphan(); +}; diff --git a/kaijuu/phoenix/gtk/settings.cpp b/kaijuu/phoenix/gtk/settings.cpp new file mode 100644 index 00000000..aeb28bba --- /dev/null +++ b/kaijuu/phoenix/gtk/settings.cpp @@ -0,0 +1,25 @@ +static Settings *settings = nullptr; + +void Settings::load() { + string path = { userpath(), ".config/phoenix/gtk.cfg" }; + configuration::load(path); +} + +void Settings::save() { + string path = { userpath(), ".config/" }; + mkdir(path, 0755); + path.append("phoenix/"); + mkdir(path, 0755); + path.append("gtk.cfg"); + configuration::save(path); +} + +Settings::Settings() { + append(frameGeometryX = 4, "frameGeometryX"); + append(frameGeometryY = 24, "frameGeometryY"); + append(frameGeometryWidth = 8, "frameGeometryWidth"); + append(frameGeometryHeight = 28, "frameGeometryHeight"); + append(menuGeometryHeight = 20, "menuGeometryHeight"); + append(statusGeometryHeight = 20, "statusGeometryHeight"); + append(windowBackgroundColor = 0xedeceb, "windowBackgroundColor"); +} diff --git a/kaijuu/phoenix/gtk/timer.cpp b/kaijuu/phoenix/gtk/timer.cpp new file mode 100644 index 00000000..d04183f8 --- /dev/null +++ b/kaijuu/phoenix/gtk/timer.cpp @@ -0,0 +1,24 @@ +static guint Timer_trigger(pTimer *self) { + //timer may have been disabled prior to triggering, so check state + if(self->timer.state.enabled) { + if(self->timer.onTimeout) self->timer.onTimeout(); + } + //callback may have disabled timer, so check state again + if(self->timer.state.enabled) { + g_timeout_add(self->timer.state.milliseconds, (GSourceFunc)Timer_trigger, (gpointer)self); + } + //kill this timer instance (it is spawned above if needed again) + return false; +} + +void pTimer::setEnabled(bool enabled) { + if(enabled) { + g_timeout_add(timer.state.milliseconds, (GSourceFunc)Timer_trigger, (gpointer)this); + } +} + +void pTimer::setInterval(unsigned milliseconds) { +} + +void pTimer::constructor() { +} diff --git a/kaijuu/phoenix/gtk/utility.cpp b/kaijuu/phoenix/gtk/utility.cpp new file mode 100644 index 00000000..29e87bb8 --- /dev/null +++ b/kaijuu/phoenix/gtk/utility.cpp @@ -0,0 +1,200 @@ +static GdkPixbuf* CreatePixbuf(const nall::image &image, bool scale = false) { + nall::image gdkImage = image; + gdkImage.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16); + if(scale) gdkImage.scale(15, 15, Interpolation::Linear); + + GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, gdkImage.width, gdkImage.height); + memcpy(gdk_pixbuf_get_pixels(pixbuf), gdkImage.data, gdkImage.width * gdkImage.height * 4); + + return pixbuf; +} + +static GtkImage* CreateImage(const nall::image &image, bool scale = false) { + GdkPixbuf *pixbuf = CreatePixbuf(image, scale); + GtkImage *gtkImage = (GtkImage*)gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); + return gtkImage; +} + +static Keyboard::Keycode Keysym(unsigned keysym) { + switch(keysym) { + case GDK_Escape: return Keyboard::Keycode::Escape; + case GDK_F1: return Keyboard::Keycode::F1; + case GDK_F2: return Keyboard::Keycode::F2; + case GDK_F3: return Keyboard::Keycode::F3; + case GDK_F4: return Keyboard::Keycode::F4; + case GDK_F5: return Keyboard::Keycode::F5; + case GDK_F6: return Keyboard::Keycode::F6; + case GDK_F7: return Keyboard::Keycode::F7; + case GDK_F8: return Keyboard::Keycode::F8; + case GDK_F9: return Keyboard::Keycode::F9; + case GDK_F10: return Keyboard::Keycode::F10; + case GDK_F11: return Keyboard::Keycode::F11; + case GDK_F12: return Keyboard::Keycode::F12; + + case GDK_Print: return Keyboard::Keycode::PrintScreen; + //Keyboard::Keycode::SysRq + case GDK_Scroll_Lock: return Keyboard::Keycode::ScrollLock; + case GDK_Pause: return Keyboard::Keycode::Pause; + //Keyboard::Keycode::Break + + case GDK_Insert: return Keyboard::Keycode::Insert; + case GDK_Delete: return Keyboard::Keycode::Delete; + case GDK_Home: return Keyboard::Keycode::Home; + case GDK_End: return Keyboard::Keycode::End; + case GDK_Prior: return Keyboard::Keycode::PageUp; + case GDK_Next: return Keyboard::Keycode::PageDown; + + case GDK_Up: return Keyboard::Keycode::Up; + case GDK_Down: return Keyboard::Keycode::Down; + case GDK_Left: return Keyboard::Keycode::Left; + case GDK_Right: return Keyboard::Keycode::Right; + + case GDK_grave: return Keyboard::Keycode::Grave; + case GDK_1: return Keyboard::Keycode::Number1; + case GDK_2: return Keyboard::Keycode::Number2; + case GDK_3: return Keyboard::Keycode::Number3; + case GDK_4: return Keyboard::Keycode::Number4; + case GDK_5: return Keyboard::Keycode::Number5; + case GDK_6: return Keyboard::Keycode::Number6; + case GDK_7: return Keyboard::Keycode::Number7; + case GDK_8: return Keyboard::Keycode::Number8; + case GDK_9: return Keyboard::Keycode::Number9; + case GDK_0: return Keyboard::Keycode::Number0; + case GDK_minus: return Keyboard::Keycode::Minus; + case GDK_equal: return Keyboard::Keycode::Equal; + case GDK_BackSpace: return Keyboard::Keycode::Backspace; + + case GDK_asciitilde: return Keyboard::Keycode::Tilde; + case GDK_exclam: return Keyboard::Keycode::Exclamation; + case GDK_at: return Keyboard::Keycode::At; + case GDK_numbersign: return Keyboard::Keycode::Pound; + case GDK_dollar: return Keyboard::Keycode::Dollar; + case GDK_percent: return Keyboard::Keycode::Percent; + case GDK_asciicircum: return Keyboard::Keycode::Power; + case GDK_ampersand: return Keyboard::Keycode::Ampersand; + case GDK_asterisk: return Keyboard::Keycode::Asterisk; + case GDK_parenleft: return Keyboard::Keycode::ParenthesisLeft; + case GDK_parenright: return Keyboard::Keycode::ParenthesisRight; + case GDK_underscore: return Keyboard::Keycode::Underscore; + case GDK_plus: return Keyboard::Keycode::Plus; + + case GDK_bracketleft: return Keyboard::Keycode::BracketLeft; + case GDK_bracketright: return Keyboard::Keycode::BracketRight; + case GDK_backslash: return Keyboard::Keycode::Backslash; + case GDK_semicolon: return Keyboard::Keycode::Semicolon; + case GDK_apostrophe: return Keyboard::Keycode::Apostrophe; + case GDK_comma: return Keyboard::Keycode::Comma; + case GDK_period: return Keyboard::Keycode::Period; + case GDK_slash: return Keyboard::Keycode::Slash; + + case GDK_braceleft: return Keyboard::Keycode::BraceLeft; + case GDK_braceright: return Keyboard::Keycode::BraceRight; + case GDK_bar: return Keyboard::Keycode::Pipe; + case GDK_colon: return Keyboard::Keycode::Colon; + case GDK_quotedbl: return Keyboard::Keycode::Quote; + case GDK_less: return Keyboard::Keycode::CaretLeft; + case GDK_greater: return Keyboard::Keycode::CaretRight; + case GDK_question: return Keyboard::Keycode::Question; + + case GDK_Tab: return Keyboard::Keycode::Tab; + case GDK_Caps_Lock: return Keyboard::Keycode::CapsLock; + case GDK_Return: return Keyboard::Keycode::Return; + case GDK_Shift_L: return Keyboard::Keycode::ShiftLeft; + case GDK_Shift_R: return Keyboard::Keycode::ShiftRight; + case GDK_Control_L: return Keyboard::Keycode::ControlLeft; + case GDK_Control_R: return Keyboard::Keycode::ControlRight; + case GDK_Super_L: return Keyboard::Keycode::SuperLeft; + case GDK_Super_R: return Keyboard::Keycode::SuperRight; + case GDK_Alt_L: return Keyboard::Keycode::AltLeft; + case GDK_Alt_R: return Keyboard::Keycode::AltRight; + case GDK_space: return Keyboard::Keycode::Space; + case GDK_Menu: return Keyboard::Keycode::Menu; + + case GDK_A: return Keyboard::Keycode::A; + case GDK_B: return Keyboard::Keycode::B; + case GDK_C: return Keyboard::Keycode::C; + case GDK_D: return Keyboard::Keycode::D; + case GDK_E: return Keyboard::Keycode::E; + case GDK_F: return Keyboard::Keycode::F; + case GDK_G: return Keyboard::Keycode::G; + case GDK_H: return Keyboard::Keycode::H; + case GDK_I: return Keyboard::Keycode::I; + case GDK_J: return Keyboard::Keycode::J; + case GDK_K: return Keyboard::Keycode::K; + case GDK_L: return Keyboard::Keycode::L; + case GDK_M: return Keyboard::Keycode::M; + case GDK_N: return Keyboard::Keycode::N; + case GDK_O: return Keyboard::Keycode::O; + case GDK_P: return Keyboard::Keycode::P; + case GDK_Q: return Keyboard::Keycode::Q; + case GDK_R: return Keyboard::Keycode::R; + case GDK_S: return Keyboard::Keycode::S; + case GDK_T: return Keyboard::Keycode::T; + case GDK_U: return Keyboard::Keycode::U; + case GDK_V: return Keyboard::Keycode::V; + case GDK_W: return Keyboard::Keycode::W; + case GDK_X: return Keyboard::Keycode::X; + case GDK_Y: return Keyboard::Keycode::Y; + case GDK_Z: return Keyboard::Keycode::Z; + + case GDK_a: return Keyboard::Keycode::a; + case GDK_b: return Keyboard::Keycode::b; + case GDK_c: return Keyboard::Keycode::c; + case GDK_d: return Keyboard::Keycode::d; + case GDK_e: return Keyboard::Keycode::e; + case GDK_f: return Keyboard::Keycode::f; + case GDK_g: return Keyboard::Keycode::g; + case GDK_h: return Keyboard::Keycode::h; + case GDK_i: return Keyboard::Keycode::i; + case GDK_j: return Keyboard::Keycode::j; + case GDK_k: return Keyboard::Keycode::k; + case GDK_l: return Keyboard::Keycode::l; + case GDK_m: return Keyboard::Keycode::m; + case GDK_n: return Keyboard::Keycode::n; + case GDK_o: return Keyboard::Keycode::o; + case GDK_p: return Keyboard::Keycode::p; + case GDK_q: return Keyboard::Keycode::q; + case GDK_r: return Keyboard::Keycode::r; + case GDK_s: return Keyboard::Keycode::s; + case GDK_t: return Keyboard::Keycode::t; + case GDK_u: return Keyboard::Keycode::u; + case GDK_v: return Keyboard::Keycode::v; + case GDK_w: return Keyboard::Keycode::w; + case GDK_x: return Keyboard::Keycode::x; + case GDK_y: return Keyboard::Keycode::y; + case GDK_z: return Keyboard::Keycode::z; + + case GDK_Num_Lock: return Keyboard::Keycode::NumLock; + case GDK_KP_Divide: return Keyboard::Keycode::Divide; + case GDK_KP_Multiply: return Keyboard::Keycode::Multiply; + case GDK_KP_Subtract: return Keyboard::Keycode::Subtract; + case GDK_KP_Add: return Keyboard::Keycode::Add; + case GDK_KP_Enter: return Keyboard::Keycode::Enter; + case GDK_KP_Decimal: return Keyboard::Keycode::Point; + + case GDK_KP_1: return Keyboard::Keycode::Keypad1; + case GDK_KP_2: return Keyboard::Keycode::Keypad2; + case GDK_KP_3: return Keyboard::Keycode::Keypad3; + case GDK_KP_4: return Keyboard::Keycode::Keypad4; + case GDK_KP_5: return Keyboard::Keycode::Keypad5; + case GDK_KP_6: return Keyboard::Keycode::Keypad6; + case GDK_KP_7: return Keyboard::Keycode::Keypad7; + case GDK_KP_8: return Keyboard::Keycode::Keypad8; + case GDK_KP_9: return Keyboard::Keycode::Keypad9; + case GDK_KP_0: return Keyboard::Keycode::Keypad0; + + case GDK_KP_Home: return Keyboard::Keycode::KeypadHome; + case GDK_KP_End: return Keyboard::Keycode::KeypadEnd; + case GDK_KP_Page_Up: return Keyboard::Keycode::KeypadPageUp; + case GDK_KP_Page_Down: return Keyboard::Keycode::KeypadPageDown; + case GDK_KP_Up: return Keyboard::Keycode::KeypadUp; + case GDK_KP_Down: return Keyboard::Keycode::KeypadDown; + case GDK_KP_Left: return Keyboard::Keycode::KeypadLeft; + case GDK_KP_Right: return Keyboard::Keycode::KeypadRight; + case GDK_KP_Begin: return Keyboard::Keycode::KeypadCenter; + case GDK_KP_Insert: return Keyboard::Keycode::KeypadInsert; + case GDK_KP_Delete: return Keyboard::Keycode::KeypadDelete; + } + return Keyboard::Keycode::None; +} diff --git a/kaijuu/phoenix/gtk/widget/button.cpp b/kaijuu/phoenix/gtk/widget/button.cpp new file mode 100644 index 00000000..6f646a25 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/button.cpp @@ -0,0 +1,53 @@ +static void Button_activate(Button *self) { + if(self->onActivate) self->onActivate(); +} + +Geometry pButton::minimumGeometry() { + Geometry geometry = pFont::geometry(widget.state.font, button.state.text); + + if(button.state.orientation == Orientation::Horizontal) { + geometry.width += button.state.image.width; + geometry.height = max(button.state.image.height, geometry.height); + } + + if(button.state.orientation == Orientation::Vertical) { + geometry.width = max(button.state.image.width, geometry.width); + geometry.height += button.state.image.height; + } + + return { 0, 0, geometry.width + 24, geometry.height + 12 }; +} + +void pButton::setImage(const image &image, Orientation orientation) { + if(image.empty() == false) { + GtkImage *gtkImage = CreateImage(image); + gtk_button_set_image(GTK_BUTTON(gtkWidget), (GtkWidget*)gtkImage); + } else { + gtk_button_set_image(GTK_BUTTON(gtkWidget), nullptr); + } + switch(orientation) { + case Orientation::Horizontal: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_LEFT); break; + case Orientation::Vertical: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_TOP); break; + } +} + +void pButton::setText(const string &text) { + gtk_button_set_label(GTK_BUTTON(gtkWidget), text); + setFont(widget.state.font); +} + +void pButton::constructor() { + gtkWidget = gtk_button_new(); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "clicked", G_CALLBACK(Button_activate), (gpointer)&button); + + setText(button.state.text); +} + +void pButton::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pButton::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/canvas.cpp b/kaijuu/phoenix/gtk/widget/canvas.cpp new file mode 100644 index 00000000..9d17dc82 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/canvas.cpp @@ -0,0 +1,70 @@ +static gboolean Canvas_expose(GtkWidget *widget, GdkEvent *event, pCanvas *self) { + cairo_t *context = gdk_cairo_create(gtk_widget_get_window(widget)); + cairo_set_source_surface(context, self->surface, 0, 0); + cairo_paint(context); + cairo_destroy(context); + return true; +} + +static gboolean Canvas_mouseLeave(GtkWidget *widget, GdkEventButton *event, pCanvas *self) { + if(self->canvas.onMouseLeave) self->canvas.onMouseLeave(); + return true; +} + +static gboolean Canvas_mouseMove(GtkWidget *widget, GdkEventButton *event, pCanvas *self) { + if(self->canvas.onMouseMove) self->canvas.onMouseMove({ (signed)event->x, (signed)event->y }); + return true; +} + +static gboolean Canvas_mousePress(GtkWidget *widget, GdkEventButton *event, pCanvas *self) { + if(self->canvas.onMousePress) switch(event->button) { + case 1: self->canvas.onMousePress(Mouse::Button::Left); break; + case 2: self->canvas.onMousePress(Mouse::Button::Middle); break; + case 3: self->canvas.onMousePress(Mouse::Button::Right); break; + } + return true; +} + +static gboolean Canvas_mouseRelease(GtkWidget *widget, GdkEventButton *event, pCanvas *self) { + if(self->canvas.onMouseRelease) switch(event->button) { + case 1: self->canvas.onMouseRelease(Mouse::Button::Left); break; + case 2: self->canvas.onMouseRelease(Mouse::Button::Middle); break; + case 3: self->canvas.onMouseRelease(Mouse::Button::Right); break; + } + return true; +} + +void pCanvas::setSize(const Size &size) { + cairo_surface_destroy(surface); + surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, canvas.state.width, canvas.state.height); +} + +void pCanvas::update() { + memcpy(cairo_image_surface_get_data(surface), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); + if(gtk_widget_get_realized(gtkWidget) == false) return; + gdk_window_invalidate_rect(gtk_widget_get_window(gtkWidget), 0, true); +} + +void pCanvas::constructor() { + surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, canvas.state.width, canvas.state.height); + memcpy(cairo_image_surface_get_data(surface), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); + gtkWidget = gtk_drawing_area_new(); + gtk_widget_set_double_buffered(gtkWidget, false); + gtk_widget_add_events(gtkWidget, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK); + g_signal_connect(G_OBJECT(gtkWidget), "button_press_event", G_CALLBACK(Canvas_mousePress), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "button_release_event", G_CALLBACK(Canvas_mouseRelease), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "leave_notify_event", G_CALLBACK(Canvas_mouseLeave), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "motion_notify_event", G_CALLBACK(Canvas_mouseMove), (gpointer)this); +} + +void pCanvas::destructor() { + gtk_widget_destroy(gtkWidget); + cairo_surface_destroy(surface); +} + +void pCanvas::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/check-box.cpp b/kaijuu/phoenix/gtk/widget/check-box.cpp new file mode 100644 index 00000000..b6493f32 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/check-box.cpp @@ -0,0 +1,40 @@ +static void CheckBox_toggle(CheckBox *self) { + self->state.checked = self->checked(); + if(self->p.locked == false && self->onToggle) self->onToggle(); +} + +bool pCheckBox::checked() { + return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtkWidget)); +} + +Geometry pCheckBox::minimumGeometry() { + Geometry geometry = pFont::geometry(widget.state.font, checkBox.state.text); + return { 0, 0, geometry.width + 28, geometry.height + 4 }; +} + +void pCheckBox::setChecked(bool checked) { + locked = true; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), checked); + locked = false; +} + +void pCheckBox::setText(const string &text) { + gtk_button_set_label(GTK_BUTTON(gtkWidget), text); +} + +void pCheckBox::constructor() { + gtkWidget = gtk_check_button_new_with_label(""); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(CheckBox_toggle), (gpointer)&checkBox); + + setChecked(checkBox.state.checked); + setText(checkBox.state.text); +} + +void pCheckBox::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pCheckBox::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/combo-box.cpp b/kaijuu/phoenix/gtk/widget/combo-box.cpp new file mode 100644 index 00000000..648d587f --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/combo-box.cpp @@ -0,0 +1,73 @@ +static void ComboBox_change(ComboBox *self) { + if(self->p.locked == false) { + self->state.selection = self->selection(); + if(self->onChange) self->onChange(); + } +} + +void pComboBox::append(const string &text) { + gtk_combo_box_append_text(GTK_COMBO_BOX(gtkWidget), text); + if(itemCounter++ == 0) setSelection(0); +} + +Geometry pComboBox::minimumGeometry() { + unsigned maximumWidth = 0; + for(auto &item : comboBox.state.text) maximumWidth = max(maximumWidth, pFont::geometry(widget.state.font, item).width); + + Geometry geometry = pFont::geometry(widget.state.font, " "); + return { 0, 0, maximumWidth + 44, geometry.height + 12 }; +} + +void pComboBox::modify(unsigned row, const string &text) { + locked = true; + unsigned position = selection(); + gtk_combo_box_remove_text(GTK_COMBO_BOX(gtkWidget), row); + gtk_combo_box_insert_text(GTK_COMBO_BOX(gtkWidget), row, text); + gtk_combo_box_set_active(GTK_COMBO_BOX(gtkWidget), position); + locked = false; +} + +void pComboBox::remove(unsigned row) { + locked = true; + unsigned position = selection(); + gtk_combo_box_remove_text(GTK_COMBO_BOX(gtkWidget), row); + if(position == row) gtk_combo_box_set_active(GTK_COMBO_BOX(gtkWidget), 0); + locked = false; +} + +void pComboBox::reset() { + locked = true; + gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(gtkWidget)))); + itemCounter = 0; + locked = false; +} + +unsigned pComboBox::selection() { + return gtk_combo_box_get_active(GTK_COMBO_BOX(gtkWidget)); +} + +void pComboBox::setSelection(unsigned row) { + locked = true; + gtk_combo_box_set_active(GTK_COMBO_BOX(gtkWidget), row); + locked = false; +} + +void pComboBox::constructor() { + itemCounter = 0; + gtkWidget = gtk_combo_box_new_text(); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "changed", G_CALLBACK(ComboBox_change), (gpointer)&comboBox); + + locked = true; + for(auto &text : comboBox.state.text) append(text); + locked = false; + setSelection(comboBox.state.selection); +} + +void pComboBox::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pComboBox::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/hex-edit.cpp b/kaijuu/phoenix/gtk/widget/hex-edit.cpp new file mode 100644 index 00000000..9c0dbdef --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/hex-edit.cpp @@ -0,0 +1,264 @@ +static bool HexEdit_keyPress(GtkWidget *widget, GdkEventKey *event, HexEdit *self) { + return self->p.keyPress(event->keyval); +} + +static bool HexEdit_scroll(GtkRange *range, GtkScrollType scroll, gdouble value, HexEdit *self) { + self->p.scroll((unsigned)value); + return false; +} + +void pHexEdit::setColumns(unsigned columns) { + setScroll(); + update(); +} + +void pHexEdit::setLength(unsigned length) { + setScroll(); + update(); +} + +void pHexEdit::setOffset(unsigned offset) { + setScroll(); + updateScroll(); + update(); +} + +void pHexEdit::setRows(unsigned rows) { + setScroll(); + update(); +} + +void pHexEdit::update() { + if(!hexEdit.onRead) { + gtk_text_buffer_set_text(textBuffer, "", -1); + return; + } + + unsigned position = cursorPosition(); + + string output; + unsigned offset = hexEdit.state.offset; + for(unsigned row = 0; row < hexEdit.state.rows; row++) { + output.append(hex<8>(offset)); + output.append(" "); + + string hexdata; + string ansidata = " "; + for(unsigned column = 0; column < hexEdit.state.columns; column++) { + if(offset < hexEdit.state.length) { + uint8_t data = hexEdit.onRead(offset++); + hexdata.append(hex<2>(data)); + hexdata.append(" "); + char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 }; + ansidata.append(buffer); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(offset >= hexEdit.state.length) break; + if(row != hexEdit.state.rows - 1) output.append("\n"); + } + + gtk_text_buffer_set_text(textBuffer, output, -1); + if(position == 0) position = 10; //start at first position where hex values can be entered + setCursorPosition(position); +} + +void pHexEdit::constructor() { + gtkWidget = gtk_hbox_new(false, 0); + + container = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(container), GTK_POLICY_NEVER, GTK_POLICY_NEVER); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(container), GTK_SHADOW_ETCHED_IN); + + subWidget = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(subWidget), false); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_NONE); + gtk_container_add(GTK_CONTAINER(container), subWidget); + g_signal_connect(G_OBJECT(subWidget), "key-press-event", G_CALLBACK(HexEdit_keyPress), (gpointer)&hexEdit); + + scrollBar = gtk_vscrollbar_new((GtkAdjustment*)0); + gtk_range_set_range(GTK_RANGE(scrollBar), 0, 255); + gtk_range_set_increments(GTK_RANGE(scrollBar), 1, 16); + gtk_widget_set_sensitive(scrollBar, false); + g_signal_connect(G_OBJECT(scrollBar), "change-value", G_CALLBACK(HexEdit_scroll), (gpointer)&hexEdit); + + gtk_box_pack_start(GTK_BOX(gtkWidget), container, true, true, 0); + gtk_box_pack_start(GTK_BOX(gtkWidget), scrollBar, false, false, 1); + + textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); + textCursor = gtk_text_buffer_get_mark(textBuffer, "insert"); + + gtk_widget_show(scrollBar); + gtk_widget_show(subWidget); + gtk_widget_show(container); + + setColumns(hexEdit.state.columns); + setRows(hexEdit.state.rows); + setLength(hexEdit.state.length); + setOffset(hexEdit.state.offset); + update(); +} + +void pHexEdit::destructor() { + gtk_widget_destroy(scrollBar); + gtk_widget_destroy(subWidget); + gtk_widget_destroy(container); + gtk_widget_destroy(gtkWidget); +} + +void pHexEdit::orphan() { + destructor(); + constructor(); +} + +unsigned pHexEdit::cursorPosition() { + GtkTextIter iter; + gtk_text_buffer_get_iter_at_mark(textBuffer, &iter, textCursor); + return gtk_text_iter_get_offset(&iter); +} + +bool pHexEdit::keyPress(unsigned scancode) { + if(!hexEdit.onRead) return false; + + unsigned position = cursorPosition(); + unsigned lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 1; + unsigned cursorY = position / lineWidth; + unsigned cursorX = position % lineWidth; + + if(scancode == GDK_Home) { + setCursorPosition(cursorY * lineWidth + 10); + return true; + } + + if(scancode == GDK_End) { + setCursorPosition(cursorY * lineWidth + 10 + (hexEdit.state.columns * 3 - 1)); + return true; + } + + if(scancode == GDK_Up) { + if(cursorY != 0) return false; + + signed newOffset = hexEdit.state.offset - hexEdit.state.columns; + if(newOffset >= 0) { + hexEdit.setOffset(newOffset); + update(); + } + return true; + } + + if(scancode == GDK_Down) { + if(cursorY != hexEdit.state.rows - 1) return false; + + signed newOffset = hexEdit.state.offset + hexEdit.state.columns; + if(newOffset + hexEdit.state.columns * hexEdit.state.rows - (hexEdit.state.columns - 1) <= hexEdit.state.length) { + hexEdit.setOffset(newOffset); + update(); + } + return true; + } + + if(scancode == GDK_Page_Up) { + signed newOffset = hexEdit.state.offset - hexEdit.state.columns * hexEdit.state.rows; + if(newOffset >= 0) { + hexEdit.setOffset(newOffset); + } else { + hexEdit.setOffset(0); + } + update(); + return true; + } + + if(scancode == GDK_Page_Down) { + signed newOffset = hexEdit.state.offset + hexEdit.state.columns * hexEdit.state.rows; + for(unsigned n = 0; n < hexEdit.state.rows; n++) { + if(newOffset + hexEdit.state.columns * hexEdit.state.rows - (hexEdit.state.columns - 1) <= hexEdit.state.length) { + hexEdit.setOffset(newOffset); + update(); + break; + } + newOffset -= hexEdit.state.columns; + } + return true; + } + + //convert scancode to hex nibble + if(scancode >= '0' && scancode <= '9') scancode = scancode - '0'; + else if(scancode >= 'A' && scancode <= 'F') scancode = scancode - 'A' + 10; + else if(scancode >= 'a' && scancode <= 'f') scancode = scancode - 'a' + 10; + else return false; //not a valid hex value + + if(cursorX >= 10) { + //not on an offset + cursorX -= 10; + if((cursorX % 3) != 2) { + //not on a space + bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low + cursorX /= 3; + if(cursorX < hexEdit.state.columns) { + //not in ANSI region + unsigned offset = hexEdit.state.offset + (cursorY * hexEdit.state.columns + cursorX); + + if(offset >= hexEdit.state.length) return false; //do not edit past end of data + uint8_t data = hexEdit.onRead(offset); + + //write modified value + if(cursorNibble == 1) { + data = (data & 0xf0) | (scancode << 0); + } else { + data = (data & 0x0f) | (scancode << 4); + } + if(hexEdit.onWrite) hexEdit.onWrite(offset, data); + + //auto-advance cursor to next nibble/byte + position++; + if(cursorNibble && cursorX != hexEdit.state.columns - 1) position++; + setCursorPosition(position); + + //refresh output to reflect modified data + update(); + } + } + } + + return true; +} + +void pHexEdit::scroll(unsigned position) { + unsigned rows = hexEdit.state.length / hexEdit.state.columns; + if(position >= rows) position = rows - 1; + hexEdit.setOffset(position * hexEdit.state.columns); +} + +void pHexEdit::setCursorPosition(unsigned position) { + GtkTextIter iter; + gtk_text_buffer_get_iter_at_mark(textBuffer, &iter, textCursor); + + //GTK+ will throw many errors to the terminal if you set iterator past end of buffer + GtkTextIter endIter; + gtk_text_buffer_get_end_iter(textBuffer, &iter); + unsigned endPosition = gtk_text_iter_get_offset(&iter); + + gtk_text_iter_set_offset(&iter, min(position, endPosition)); + gtk_text_buffer_place_cursor(textBuffer, &iter); +} + +void pHexEdit::setScroll() { + unsigned rows = hexEdit.state.length / hexEdit.state.columns; + if(rows) rows--; + if(rows) { + gtk_range_set_range(GTK_RANGE(scrollBar), 0, rows); + gtk_widget_set_sensitive(scrollBar, true); + } else { + gtk_widget_set_sensitive(scrollBar, false); + } +} + +void pHexEdit::updateScroll() { + unsigned row = hexEdit.state.offset / hexEdit.state.columns; + gtk_range_set_value(GTK_RANGE(scrollBar), row); +} diff --git a/kaijuu/phoenix/gtk/widget/horizontal-scroll-bar.cpp b/kaijuu/phoenix/gtk/widget/horizontal-scroll-bar.cpp new file mode 100644 index 00000000..0d765e92 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,42 @@ +static void HorizontalScrollBar_change(HorizontalScrollBar *self) { + if(self->state.position == self->position()) return; + self->state.position = self->position(); + if(self->p.locked == false && self->onChange) self->onChange(); +} + +Geometry pHorizontalScrollBar::minimumGeometry() { + return { 0, 0, 0, 20 }; +} + +unsigned pHorizontalScrollBar::position() { + return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget)); +} + +void pHorizontalScrollBar::setLength(unsigned length) { + locked = true; + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); + locked = false; +} + +void pHorizontalScrollBar::setPosition(unsigned position) { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +void pHorizontalScrollBar::constructor() { + gtkWidget = gtk_hscrollbar_new(0); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalScrollBar_change), (gpointer)&horizontalScrollBar); + + setLength(horizontalScrollBar.state.length); + setPosition(horizontalScrollBar.state.position); +} + +void pHorizontalScrollBar::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pHorizontalScrollBar::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/horizontal-slider.cpp b/kaijuu/phoenix/gtk/widget/horizontal-slider.cpp new file mode 100644 index 00000000..2d19bae6 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/horizontal-slider.cpp @@ -0,0 +1,41 @@ +static void HorizontalSlider_change(HorizontalSlider *self) { + if(self->state.position == self->position()) return; + self->state.position = self->position(); + if(self->onChange) self->onChange(); +} + +Geometry pHorizontalSlider::minimumGeometry() { + return { 0, 0, 0, 20 }; +} + +unsigned pHorizontalSlider::position() { + return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget)); +} + +void pHorizontalSlider::setLength(unsigned length) { + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); +} + +void pHorizontalSlider::setPosition(unsigned position) { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +void pHorizontalSlider::constructor() { + gtkWidget = gtk_hscale_new_with_range(0, 100, 1); + gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)&horizontalSlider); + + setLength(horizontalSlider.state.length); + setPosition(horizontalSlider.state.position); +} + +void pHorizontalSlider::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pHorizontalSlider::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/label.cpp b/kaijuu/phoenix/gtk/widget/label.cpp new file mode 100644 index 00000000..8b5cec4f --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/label.cpp @@ -0,0 +1,24 @@ +Geometry pLabel::minimumGeometry() { + Geometry geometry = pFont::geometry(widget.state.font, label.state.text); + return { 0, 0, geometry.width, geometry.height }; +} + +void pLabel::setText(const string &text) { + gtk_label_set_text(GTK_LABEL(gtkWidget), text); +} + +void pLabel::constructor() { + gtkWidget = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(gtkWidget), 0.0, 0.5); + + setText(label.state.text); +} + +void pLabel::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pLabel::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/line-edit.cpp b/kaijuu/phoenix/gtk/widget/line-edit.cpp new file mode 100644 index 00000000..8dbe9ef4 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/line-edit.cpp @@ -0,0 +1,45 @@ +static void LineEdit_activate(LineEdit *self) { + if(self->onActivate) self->onActivate(); +} + +static void LineEdit_change(LineEdit *self) { + self->state.text = self->text(); + if(self->p.locked == false && self->onChange) self->onChange(); +} + +Geometry pLineEdit::minimumGeometry() { + Geometry geometry = pFont::geometry(widget.state.font, lineEdit.state.text); + return { 0, 0, geometry.width + 10, geometry.height + 10 }; +} + +void pLineEdit::setEditable(bool editable) { + gtk_editable_set_editable(GTK_EDITABLE(gtkWidget), editable); +} + +void pLineEdit::setText(const string &text) { + locked = true; + gtk_entry_set_text(GTK_ENTRY(gtkWidget), text); + locked = false; +} + +string pLineEdit::text() { + return gtk_entry_get_text(GTK_ENTRY(gtkWidget)); +} + +void pLineEdit::constructor() { + gtkWidget = gtk_entry_new(); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "activate", G_CALLBACK(LineEdit_activate), (gpointer)&lineEdit); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "changed", G_CALLBACK(LineEdit_change), (gpointer)&lineEdit); + + setEditable(lineEdit.state.editable); + setText(lineEdit.state.text); +} + +void pLineEdit::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pLineEdit::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/list-view.cpp b/kaijuu/phoenix/gtk/widget/list-view.cpp new file mode 100644 index 00000000..5572c1f7 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/list-view.cpp @@ -0,0 +1,217 @@ +static void ListView_activate(ListView *self) { + if(self->onActivate) self->onActivate(); +} + +static void ListView_change(ListView *self) { + if(self->state.selected == false || self->state.selection != self->selection()) { + self->state.selected = true; + self->state.selection = self->selection(); + if(self->onChange) self->onChange(); + } +} + +static void ListView_toggle(GtkCellRendererToggle *cell, gchar *path, ListView *self) { + unsigned row = decimal(path); + self->setChecked(row, !self->checked(row)); + if(self->onToggle) self->onToggle(row); +} + +void pListView::append(const lstring &text) { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + for(unsigned n = 0; n < text.size(); n++) gtk_list_store_set(store, &iter, 1 + n * 2 + 1, (const char*)text[n], -1); +} + +void pListView::autoSizeColumns() { + gtk_tree_view_columns_autosize(GTK_TREE_VIEW(subWidget)); +} + +bool pListView::checked(unsigned row) { + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreeIter iter; + bool state; + if(gtk_tree_model_get_iter_from_string(model, &iter, string(row)) == false) return false; + gtk_tree_model_get(model, &iter, 0, &state, -1); + return state; +} + +void pListView::modify(unsigned row, const lstring &text) { + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreeIter iter; + gtk_tree_model_get_iter_from_string(model, &iter, string(row)); + for(unsigned n = 0; n < text.size(); n++) gtk_list_store_set(store, &iter, 1 + n * 2 + 1, (const char*)text[n], -1); +} + +void pListView::remove(unsigned row) { + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreeIter iter; + gtk_tree_model_get_iter_from_string(model, &iter, string(row)); + gtk_list_store_remove(store, &iter); +} + +void pListView::reset() { + listView.state.selected = false; + listView.state.selection = 0; + gtk_list_store_clear(GTK_LIST_STORE(store)); + gtk_tree_view_set_model(GTK_TREE_VIEW(subWidget), GTK_TREE_MODEL(store)); + //reset gtk_scrolled_window scrollbar position to 0,0 (top-left), as ListView is now empty + gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(gtkWidget), 0); + gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(gtkWidget), 0); +} + +bool pListView::selected() { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); + return gtk_tree_selection_get_selected(selection, 0, 0); +} + +unsigned pListView::selection() { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(selection, 0, &iter) == false) return listView.state.selection; + char *path = gtk_tree_model_get_string_from_iter(model, &iter); + unsigned row = decimal(path); + g_free(path); + return row; +} + +void pListView::setCheckable(bool checkable) { + gtk_cell_renderer_set_visible(column(0).checkbox, checkable); +} + +void pListView::setChecked(unsigned row, bool checked) { + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreeIter iter; + gtk_tree_model_get_iter_from_string(model, &iter, string(row)); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, checked, -1); +} + +void pListView::setHeaderText(const lstring &text) { + destructor(); + constructor(); +} + +void pListView::setHeaderVisible(bool visible) { + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(subWidget), visible); +} + +void pListView::setImage(unsigned row, unsigned column, const nall::image &image) { + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreeIter iter; + gtk_tree_model_get_iter_from_string(model, &iter, string(row)); + if(image.empty() == false) { + GdkPixbuf *pixbuf = CreatePixbuf(image, true); + gtk_list_store_set(store, &iter, 1 + column * 2, pixbuf, -1); + } else { + gtk_list_store_set(store, &iter, 1 + column * 2, nullptr, -1); + } +} + +void pListView::setSelected(bool selected) { + if(selected == false) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); + gtk_tree_selection_unselect_all(selection); + } else { + setSelection(listView.state.selection); + } +} + +void pListView::setSelection(unsigned row) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + gtk_tree_selection_unselect_all(selection); + GtkTreeIter iter; + if(gtk_tree_model_get_iter_from_string(model, &iter, string(row)) == false) return; + gtk_tree_selection_select_iter(selection, &iter); + + //scroll window to selected item + char *path = gtk_tree_model_get_string_from_iter(model, &iter); + GtkTreePath *treePath = gtk_tree_path_new_from_string(path); + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(subWidget), treePath, nullptr, true, 0.5, 0.0); + gtk_tree_path_free(treePath); + g_free(path); +} + +void pListView::constructor() { + gtkWidget = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); + + lstring headerText = listView.state.headerText; + if(headerText.size() == 0) headerText.append(""); //ListView must have at least one column + + column.reset(); + vector gtype; + for(auto &text : headerText) { + GtkColumn cell; + cell.label = gtk_label_new(text); + cell.column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_resizable(cell.column, true); + gtk_tree_view_column_set_title(cell.column, ""); + + if(column.size() == 0) { //first column checkbox + cell.checkbox = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(cell.column, cell.checkbox, false); + gtk_tree_view_column_set_attributes(cell.column, cell.checkbox, "active", gtype.size(), nullptr); + gtype.append(G_TYPE_BOOLEAN); + g_signal_connect(cell.checkbox, "toggled", G_CALLBACK(ListView_toggle), (gpointer)&listView); + } + + cell.icon = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(cell.column, cell.icon, false); + gtk_tree_view_column_set_attributes(cell.column, cell.icon, "pixbuf", gtype.size(), nullptr); + gtype.append(GDK_TYPE_PIXBUF); + + cell.text = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(cell.column, cell.text, false); + gtk_tree_view_column_set_attributes(cell.column, cell.text, "text", gtype.size(), nullptr); + gtype.append(G_TYPE_STRING); + + column.append(cell); + } + + store = gtk_list_store_newv(gtype.size(), gtype.data()); + subWidget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); + g_object_unref(G_OBJECT(store)); + + for(auto &cell : column) { + gtk_tree_view_column_set_widget(GTK_TREE_VIEW_COLUMN(cell.column), cell.label); + gtk_tree_view_append_column(GTK_TREE_VIEW(subWidget), cell.column); + gtk_widget_show(cell.label); + } + + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(subWidget), headerText.size() >= 2); //two or more columns + checkbox column + gtk_tree_view_set_search_column(GTK_TREE_VIEW(subWidget), 2); + + g_signal_connect_swapped(G_OBJECT(subWidget), "cursor-changed", G_CALLBACK(ListView_change), (gpointer)&listView); + g_signal_connect_swapped(G_OBJECT(subWidget), "row-activated", G_CALLBACK(ListView_activate), (gpointer)&listView); + + gtk_widget_show(subWidget); + + setHeaderVisible(listView.state.headerVisible); + setCheckable(listView.state.checkable); + for(auto &text : listView.state.text) append(text); + for(unsigned n = 0; n < listView.state.checked.size(); n++) setChecked(n, listView.state.checked[n]); + if(listView.state.selected) setSelection(listView.state.selection); + autoSizeColumns(); +} + +void pListView::destructor() { + gtk_widget_destroy(subWidget); + gtk_widget_destroy(gtkWidget); +} + +void pListView::orphan() { + destructor(); + constructor(); +} + +void pListView::setFocused() { + gtk_widget_grab_focus(subWidget); +} + +void pListView::setFont(const string &font) { + pFont::setFont(gtkWidget, font); + for(auto &cell : column) pFont::setFont(cell.label, font); +} diff --git a/kaijuu/phoenix/gtk/widget/progress-bar.cpp b/kaijuu/phoenix/gtk/widget/progress-bar.cpp new file mode 100644 index 00000000..972170b8 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/progress-bar.cpp @@ -0,0 +1,23 @@ +Geometry pProgressBar::minimumGeometry() { + return { 0, 0, 0, 25 }; +} + +void pProgressBar::setPosition(unsigned position) { + position = position <= 100 ? position : 0; + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkWidget), (double)position / 100.0); +} + +void pProgressBar::constructor() { + gtkWidget = gtk_progress_bar_new(); + + setPosition(progressBar.state.position); +} + +void pProgressBar::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pProgressBar::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/radio-box.cpp b/kaijuu/phoenix/gtk/widget/radio-box.cpp new file mode 100644 index 00000000..36aff3fa --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/radio-box.cpp @@ -0,0 +1,50 @@ +static void RadioBox_activate(RadioBox *self) { + if(self->p.locked == false && self->checked() && self->onActivate) self->onActivate(); +} + +bool pRadioBox::checked() { + return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtkWidget)); +} + +Geometry pRadioBox::minimumGeometry() { + Geometry geometry = pFont::geometry(widget.state.font, radioBox.state.text); +//Font &font = pWidget::font(); +//Geometry geometry = font.geometry(radioBox.state.text); + return { 0, 0, geometry.width + 28, geometry.height + 4 }; +} + +void pRadioBox::setChecked() { + locked = true; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), true); + locked = false; +} + +void pRadioBox::setGroup(const set &group) { + for(unsigned n = 0; n < group.size(); n++) { + if(n == 0) continue; + GSList *currentGroup = gtk_radio_button_get_group(GTK_RADIO_BUTTON(group[0].p.gtkWidget)); + if(currentGroup != gtk_radio_button_get_group(GTK_RADIO_BUTTON(gtkWidget))) { + gtk_radio_button_set_group(GTK_RADIO_BUTTON(gtkWidget), currentGroup); + } + } +} + +void pRadioBox::setText(const string &text) { + gtk_button_set_label(GTK_BUTTON(gtkWidget), text); +} + +void pRadioBox::constructor() { + gtkWidget = gtk_radio_button_new_with_label(0, ""); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(RadioBox_activate), (gpointer)&radioBox); + + setText(radioBox.state.text); +} + +void pRadioBox::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pRadioBox::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/text-edit.cpp b/kaijuu/phoenix/gtk/widget/text-edit.cpp new file mode 100644 index 00000000..08812fb3 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/text-edit.cpp @@ -0,0 +1,66 @@ +static void TextEdit_change(TextEdit *self) { + self->state.text = self->text(); + if(self->p.locked == false && self->onChange) self->onChange(); +} + +void pTextEdit::setCursorPosition(unsigned position) { + GtkTextMark *mark = gtk_text_buffer_get_mark(textBuffer, "insert"); + GtkTextIter iter; + gtk_text_buffer_get_end_iter(textBuffer, &iter); + gtk_text_iter_set_offset(&iter, min(position, gtk_text_iter_get_offset(&iter))); + gtk_text_buffer_place_cursor(textBuffer, &iter); + gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(subWidget), mark); +} + +void pTextEdit::setEditable(bool editable) { + gtk_text_view_set_editable(GTK_TEXT_VIEW(subWidget), editable); +} + +void pTextEdit::setText(const string &text) { + locked = true; + gtk_text_buffer_set_text(textBuffer, text, -1); + locked = false; +} + +void pTextEdit::setWordWrap(bool wordWrap) { + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), wordWrap ? GTK_WRAP_WORD_CHAR : GTK_WRAP_NONE); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), + wordWrap ? GTK_POLICY_NEVER : GTK_POLICY_ALWAYS, + GTK_POLICY_ALWAYS); +} + +string pTextEdit::text() { + GtkTextIter start, end; + gtk_text_buffer_get_start_iter(textBuffer, &start); + gtk_text_buffer_get_end_iter(textBuffer, &end); + char *temp = gtk_text_buffer_get_text(textBuffer, &start, &end, true); + string text = temp; + g_free(temp); + return text; +} + +void pTextEdit::constructor() { + gtkWidget = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); + subWidget = gtk_text_view_new(); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_WORD_CHAR); + gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); + textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); + g_signal_connect_swapped(G_OBJECT(textBuffer), "changed", G_CALLBACK(TextEdit_change), (gpointer)&textEdit); + gtk_widget_show(subWidget); + + setEditable(textEdit.state.editable); + setText(textEdit.state.text); + setWordWrap(textEdit.state.wordWrap); +} + +void pTextEdit::destructor() { + gtk_widget_destroy(subWidget); + gtk_widget_destroy(gtkWidget); +} + +void pTextEdit::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/vertical-scroll-bar.cpp b/kaijuu/phoenix/gtk/widget/vertical-scroll-bar.cpp new file mode 100644 index 00000000..e3bde589 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/vertical-scroll-bar.cpp @@ -0,0 +1,42 @@ +static void VerticalScrollBar_change(VerticalScrollBar *self) { + if(self->state.position == self->position()) return; + self->state.position = self->position(); + if(self->p.locked == false && self->onChange) self->onChange(); +} + +Geometry pVerticalScrollBar::minimumGeometry() { + return { 0, 0, 20, 0 }; +} + +unsigned pVerticalScrollBar::position() { + return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget)); +} + +void pVerticalScrollBar::setLength(unsigned length) { + locked = true; + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); + locked = false; +} + +void pVerticalScrollBar::setPosition(unsigned position) { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +void pVerticalScrollBar::constructor() { + gtkWidget = gtk_vscrollbar_new(0); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalScrollBar_change), (gpointer)&verticalScrollBar); + + setLength(verticalScrollBar.state.length); + setPosition(verticalScrollBar.state.position); +} + +void pVerticalScrollBar::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pVerticalScrollBar::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/vertical-slider.cpp b/kaijuu/phoenix/gtk/widget/vertical-slider.cpp new file mode 100644 index 00000000..3c68489e --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/vertical-slider.cpp @@ -0,0 +1,41 @@ +static void VerticalSlider_change(VerticalSlider *self) { + if(self->state.position == self->position()) return; + self->state.position = self->position(); + if(self->onChange) self->onChange(); +} + +Geometry pVerticalSlider::minimumGeometry() { + return { 0, 0, 20, 0 }; +} + +unsigned pVerticalSlider::position() { + return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget)); +} + +void pVerticalSlider::setLength(unsigned length) { + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); +} + +void pVerticalSlider::setPosition(unsigned position) { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +void pVerticalSlider::constructor() { + gtkWidget = gtk_vscale_new_with_range(0, 100, 1); + gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)&verticalSlider); + + setLength(verticalSlider.state.length); + setPosition(verticalSlider.state.position); +} + +void pVerticalSlider::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pVerticalSlider::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/viewport.cpp b/kaijuu/phoenix/gtk/widget/viewport.cpp new file mode 100644 index 00000000..e842a2e5 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/viewport.cpp @@ -0,0 +1,58 @@ +static gboolean Viewport_mouseLeave(GtkWidget *widget, GdkEventButton *event, pViewport *self) { + if(self->viewport.onMouseLeave) self->viewport.onMouseLeave(); + return true; +} + +static gboolean Viewport_mouseMove(GtkWidget *widget, GdkEventButton *event, pViewport *self) { + if(self->viewport.onMouseMove) self->viewport.onMouseMove({ (signed)event->x, (signed)event->y }); + return true; +} + +static gboolean Viewport_mousePress(GtkWidget *widget, GdkEventButton *event, pViewport *self) { + if(self->viewport.onMousePress) switch(event->button) { + case 1: self->viewport.onMousePress(Mouse::Button::Left); break; + case 2: self->viewport.onMousePress(Mouse::Button::Middle); break; + case 3: self->viewport.onMousePress(Mouse::Button::Right); break; + } + return true; +} + +static gboolean Viewport_mouseRelease(GtkWidget *widget, GdkEventButton *event, pViewport *self) { + if(self->viewport.onMouseRelease) switch(event->button) { + case 1: self->viewport.onMouseRelease(Mouse::Button::Left); break; + case 2: self->viewport.onMouseRelease(Mouse::Button::Middle); break; + case 3: self->viewport.onMouseRelease(Mouse::Button::Right); break; + } + return true; +} + +uintptr_t pViewport::handle() { + return GDK_WINDOW_XID(gtk_widget_get_window(gtkWidget)); +} + +void pViewport::constructor() { + gtkWidget = gtk_drawing_area_new(); +//gtk_widget_set_double_buffered(gtkWidget, false); + gtk_widget_add_events(gtkWidget, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK); + g_signal_connect(G_OBJECT(gtkWidget), "button_press_event", G_CALLBACK(Viewport_mousePress), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "button_release_event", G_CALLBACK(Viewport_mouseRelease), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "leave_notify_event", G_CALLBACK(Viewport_mouseLeave), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "motion_notify_event", G_CALLBACK(Viewport_mouseMove), (gpointer)this); + + GdkColor color; + color.pixel = 0; + color.red = 0; + color.green = 0; + color.blue = 0; + gtk_widget_modify_bg(gtkWidget, GTK_STATE_NORMAL, &color); +} + +void pViewport::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pViewport::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/widget/widget.cpp b/kaijuu/phoenix/gtk/widget/widget.cpp new file mode 100644 index 00000000..dceb8266 --- /dev/null +++ b/kaijuu/phoenix/gtk/widget/widget.cpp @@ -0,0 +1,47 @@ +Geometry pWidget::minimumGeometry() { + return { 0, 0, 0, 0 }; +} + +bool pWidget::enabled() { + return gtk_widget_get_sensitive(gtkWidget); +} + +void pWidget::setEnabled(bool enabled) { + if(widget.state.abstract) enabled = false; + if(sizable.state.layout && sizable.state.layout->enabled() == false) enabled = false; + gtk_widget_set_sensitive(gtkWidget, enabled); +} + +void pWidget::setFocused() { + gtk_widget_grab_focus(gtkWidget); +} + +void pWidget::setFont(const string &font) { + pFont::setFont(gtkWidget, font); +} + +void pWidget::setGeometry(const Geometry &geometry) { + if(sizable.window() && sizable.window()->visible()) gtk_fixed_move(GTK_FIXED(sizable.window()->p.formContainer), gtkWidget, geometry.x, geometry.y); + unsigned width = (signed)geometry.width <= 0 ? 1U : geometry.width; + unsigned height = (signed)geometry.height <= 0 ? 1U : geometry.height; + gtk_widget_set_size_request(gtkWidget, width, height); +} + +void pWidget::setVisible(bool visible) { + if(widget.state.abstract) visible = false; + if(sizable.state.layout && sizable.state.layout->visible() == false) visible = false; + gtk_widget_set_visible(gtkWidget, visible); +} + +void pWidget::constructor() { + if(widget.state.abstract) gtkWidget = gtk_label_new(""); +} + +void pWidget::destructor() { + if(widget.state.abstract) gtk_widget_destroy(gtkWidget); +} + +void pWidget::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/gtk/window.cpp b/kaijuu/phoenix/gtk/window.cpp new file mode 100644 index 00000000..ae1521a3 --- /dev/null +++ b/kaijuu/phoenix/gtk/window.cpp @@ -0,0 +1,352 @@ +static gint Window_close(GtkWidget *widget, GdkEvent *event, Window *window) { + window->state.ignore = false; + if(window->onClose) window->onClose(); + if(window->state.ignore == false) window->setVisible(false); + return true; +} + +static gboolean Window_expose(GtkWidget *widget, GdkEvent *event, Window *window) { + if(window->state.backgroundColorOverride == false) return false; + cairo_t *context = gdk_cairo_create(widget->window); + + Color color = window->backgroundColor(); + double red = (double)color.red / 255.0; + double green = (double)color.green / 255.0; + double blue = (double)color.blue / 255.0; + double alpha = (double)color.alpha / 255.0; + + if(gdk_screen_is_composited(gdk_screen_get_default())) { + 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 gboolean Window_configure(GtkWidget *widget, GdkEvent *event, Window *window) { + if(gtk_widget_get_realized(window->p.widget) == false) return false; + GdkWindow *gdkWindow = gtk_widget_get_window(widget); + + GdkRectangle border, client; + gdk_window_get_frame_extents(gdkWindow, &border); + gdk_window_get_geometry(gdkWindow, 0, 0, &client.width, &client.height, 0); + gdk_window_get_origin(gdkWindow, &client.x, &client.y); + + if(window->state.fullScreen == false) { + //update geometry settings + settings->frameGeometryX = client.x - border.x; + settings->frameGeometryY = client.y - border.y; + settings->frameGeometryWidth = border.width - client.width; + settings->frameGeometryHeight = border.height - client.height; + if(window->state.backgroundColorOverride == false) { + GdkColor color = widget->style->bg[GTK_STATE_NORMAL]; + settings->windowBackgroundColor + = ((uint8_t)(color.red >> 8) << 16) + + ((uint8_t)(color.green >> 8) << 8) + + ((uint8_t)(color.blue >> 8) << 0); + } + settings->save(); + } + + Geometry geometry = { + client.x, + client.y + window->p.menuHeight(), + client.width, + client.height - window->p.menuHeight() - window->p.statusHeight() + }; + + //move + if(geometry.x != window->state.geometry.x || geometry.y != window->state.geometry.y) { + if(window->state.fullScreen == false) { + window->state.geometry.x = geometry.x; + window->state.geometry.y = geometry.y; + } + if(window->p.locked == false && window->onMove) window->onMove(); + } + + //size + if(geometry.width != window->state.geometry.width || geometry.height != window->state.geometry.height) { + window->p.onSizePending = true; + } + + return false; +} + +static gboolean Window_keyPressEvent(GtkWidget *widget, GdkEventKey *event, Window *window) { + Keyboard::Keycode key = Keysym(event->keyval); + if(key != Keyboard::Keycode::None && window->onKeyPress) window->onKeyPress(key); + return false; +} + +static gboolean Window_keyReleaseEvent(GtkWidget *widget, GdkEventKey *event, Window *window) { + Keyboard::Keycode key = Keysym(event->keyval); + if(key != Keyboard::Keycode::None && window->onKeyRelease) window->onKeyRelease(key); + return false; +} + +static void Window_sizeAllocate(GtkWidget *widget, GtkAllocation *allocation, Window *window) { + //size-allocate sent from gtk_fixed_move(); detect if layout unchanged and return + if(allocation->width == window->p.lastAllocation.width + && allocation->height == window->p.lastAllocation.height) return; + + window->state.geometry.width = allocation->width; + window->state.geometry.height = allocation->height; + + for(auto &layout : window->state.layout) { + Geometry geometry = window->geometry(); + geometry.x = geometry.y = 0; + layout.setGeometry(geometry); + } + + if(window->p.onSizePending && window->p.locked == false && window->onSize) { + window->p.onSizePending = false; + window->onSize(); + } + + window->p.lastAllocation = *allocation; +} + +static void Window_sizeRequest(GtkWidget *widget, GtkRequisition *requisition, Window *window) { + requisition->width = window->state.geometry.width; + requisition->height = window->state.geometry.height; +} + +Window& pWindow::none() { + static Window *window = nullptr; + if(window == nullptr) window = new Window; + return *window; +} + +void pWindow::append(Layout &layout) { + Geometry geometry = this->geometry(); + geometry.x = geometry.y = 0; + layout.setGeometry(geometry); +} + +void pWindow::append(Menu &menu) { + if(window.state.menuFont != "") menu.p.setFont(window.state.menuFont); + else menu.p.setFont("Sans, 8"); + gtk_menu_shell_append(GTK_MENU_SHELL(this->menu), menu.p.widget); + gtk_widget_show(menu.p.widget); +} + +void pWindow::append(Widget &widget) { + ((Sizable&)widget).state.window = &window; + gtk_fixed_put(GTK_FIXED(formContainer), widget.p.gtkWidget, 0, 0); + if(widget.state.font != "") widget.p.setFont(widget.state.font); + else if(window.state.widgetFont != "") widget.p.setFont(window.state.widgetFont); + else widget.p.setFont("Sans, 8"); + widget.setVisible(widget.visible()); +} + +Color pWindow::backgroundColor() { + if(window.state.backgroundColorOverride) return window.state.backgroundColor; + return { + (uint8_t)(settings->windowBackgroundColor >> 16), + (uint8_t)(settings->windowBackgroundColor >> 8), + (uint8_t)(settings->windowBackgroundColor >> 0), + 255 + }; +} + +Geometry pWindow::frameMargin() { + if(window.state.fullScreen) return { + 0, + menuHeight(), + 0, + menuHeight() + statusHeight() + }; + + return { + settings->frameGeometryX, + settings->frameGeometryY + menuHeight(), + settings->frameGeometryWidth, + settings->frameGeometryHeight + menuHeight() + statusHeight() + }; +} + +bool pWindow::focused() { + return gtk_window_is_active(GTK_WINDOW(widget)); +} + +Geometry pWindow::geometry() { + if(window.state.fullScreen == true) return { + 0, + menuHeight(), + Desktop::size().width, + Desktop::size().height - menuHeight() - statusHeight() + }; + + return window.state.geometry; +} + +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { + menu.p.orphan(); +} + +void pWindow::remove(Widget &widget) { + widget.p.orphan(); +} + +void pWindow::setBackgroundColor(const Color &color) { + GdkColor gdkColor; + gdkColor.pixel = (color.red << 16) | (color.green << 8) | (color.blue << 0); + gdkColor.red = (color.red << 8) | (color.red << 0); + gdkColor.green = (color.green << 8) | (color.green << 0); + gdkColor.blue = (color.blue << 8) | (color.blue << 0); + gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &gdkColor); +} + +void pWindow::setFocused() { + gtk_window_present(GTK_WINDOW(widget)); +} + +void pWindow::setFullScreen(bool fullScreen) { + if(fullScreen == false) { + gtk_window_unfullscreen(GTK_WINDOW(widget)); + } else { + gtk_window_fullscreen(GTK_WINDOW(widget)); + } +} + +void pWindow::setGeometry(const Geometry &geometry) { + Geometry margin = frameMargin(); + gtk_window_move(GTK_WINDOW(widget), geometry.x - margin.x, geometry.y - margin.y); + + GdkGeometry geom; + geom.min_width = window.state.resizable ? 1 : window.state.geometry.width; + geom.min_height = window.state.resizable ? 1 : window.state.geometry.height; + gtk_window_set_geometry_hints(GTK_WINDOW(widget), GTK_WIDGET(widget), &geom, GDK_HINT_MIN_SIZE); + +//gtk_window_set_policy(GTK_WINDOW(widget), true, true, false); + gtk_widget_set_size_request(formContainer, geometry.width, geometry.height); + gtk_window_resize(GTK_WINDOW(widget), geometry.width, geometry.height + menuHeight() + statusHeight()); +} + +void pWindow::setMenuFont(const string &font) { + for(auto &item : window.state.menu) item.p.setFont(font); +} + +void pWindow::setMenuVisible(bool visible) { + gtk_widget_set_visible(menu, visible); +} + +void pWindow::setModal(bool modal) { + gtk_window_set_modal(GTK_WINDOW(widget), modal); +} + +void pWindow::setResizable(bool resizable) { + gtk_window_set_resizable(GTK_WINDOW(widget), resizable); + gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(status), resizable); +} + +void pWindow::setStatusFont(const string &font) { + pFont::setFont(status, font); +} + +void pWindow::setStatusText(const string &text) { + gtk_statusbar_pop(GTK_STATUSBAR(status), 1); + gtk_statusbar_push(GTK_STATUSBAR(status), 1, text); +} + +void pWindow::setStatusVisible(bool visible) { + gtk_widget_set_visible(status, visible); +} + +void pWindow::setTitle(const string &text) { + gtk_window_set_title(GTK_WINDOW(widget), text); +} + +void pWindow::setVisible(bool visible) { + gtk_widget_set_visible(widget, visible); + if(visible) { + if(gtk_widget_get_visible(menu)) { + GtkAllocation allocation; + gtk_widget_get_allocation(menu, &allocation); + settings->menuGeometryHeight = allocation.height; + } + + if(gtk_widget_get_visible(status)) { + GtkAllocation allocation; + gtk_widget_get_allocation(status, &allocation); + settings->statusGeometryHeight = allocation.height; + } + } +} + +void pWindow::setWidgetFont(const string &font) { + for(auto &item : window.state.widget) { + if(item.state.font == "") item.setFont(font); + } +} + +void pWindow::constructor() { + lastAllocation.width = 0; + lastAllocation.height = 0; + onSizePending = false; + + widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + if(gdk_screen_is_composited(gdk_screen_get_default())) { + gtk_widget_set_colormap(widget, gdk_screen_get_rgba_colormap(gdk_screen_get_default())); + } else { + gtk_widget_set_colormap(widget, gdk_screen_get_rgb_colormap(gdk_screen_get_default())); + } + + gtk_window_set_resizable(GTK_WINDOW(widget), true); + #if GTK_MAJOR_VERSION >= 3 + gtk_window_set_has_resize_grip(GTK_WINDOW(widget), false); + #endif + + gtk_widget_set_app_paintable(widget, true); + gtk_widget_add_events(widget, GDK_CONFIGURE); + + menuContainer = gtk_vbox_new(false, 0); + gtk_container_add(GTK_CONTAINER(widget), menuContainer); + gtk_widget_show(menuContainer); + + menu = gtk_menu_bar_new(); + gtk_box_pack_start(GTK_BOX(menuContainer), menu, false, false, 0); + + formContainer = gtk_fixed_new(); + gtk_box_pack_start(GTK_BOX(menuContainer), formContainer, true, true, 0); + gtk_widget_show(formContainer); + + statusContainer = gtk_event_box_new(); + status = gtk_statusbar_new(); + gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(status), true); + gtk_container_add(GTK_CONTAINER(statusContainer), status); + gtk_box_pack_start(GTK_BOX(menuContainer), statusContainer, false, false, 0); + gtk_widget_show(statusContainer); + + setTitle(""); + setResizable(window.state.resizable); + setGeometry(window.state.geometry); + setMenuFont("Sans, 8"); + setStatusFont("Sans, 8"); + + g_signal_connect(G_OBJECT(widget), "delete-event", G_CALLBACK(Window_close), (gpointer)&window); + g_signal_connect(G_OBJECT(widget), "expose-event", G_CALLBACK(Window_expose), (gpointer)&window); + g_signal_connect(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)&window); + g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(Window_keyPressEvent), (gpointer)&window); + g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(Window_keyPressEvent), (gpointer)&window); + + g_signal_connect(G_OBJECT(formContainer), "size-allocate", G_CALLBACK(Window_sizeAllocate), (gpointer)&window); + g_signal_connect(G_OBJECT(formContainer), "size-request", G_CALLBACK(Window_sizeRequest), (gpointer)&window); +} + +unsigned pWindow::menuHeight() { + return window.state.menuVisible ? settings->menuGeometryHeight : 0; +} + +unsigned pWindow::statusHeight() { + return window.state.statusVisible ? settings->statusGeometryHeight : 0; +} diff --git a/kaijuu/phoenix/phoenix.cpp b/kaijuu/phoenix/phoenix.cpp new file mode 100644 index 00000000..eaa66b97 --- /dev/null +++ b/kaijuu/phoenix/phoenix.cpp @@ -0,0 +1,52 @@ +#ifndef PHOENIX_CPP +#define PHOENIX_CPP + +#if defined(PHOENIX_WINDOWS) + #define UNICODE + #define WINVER 0x0501 + #define _WIN32_WINNT 0x0501 + #define _WIN32_IE 0x0600 + #define __MSVCRT_VERSION__ 0x0601 + #define NOMINMAX + + #include + #include + #include + #include + #include + #include + #include + #include +#elif defined(PHOENIX_QT) + #include + #include + #include + #define XK_MISCELLANY + #define XK_LATIN1 + #include + #include + #undef XK_MISCELLANY + #undef XK_LATIN1 + #include +#elif defined(PHOENIX_GTK) + #include + #include + #include + #include + #include + #include + #include + #include +#elif defined(PHOENIX_REFERENCE) +#else + #error "phoenix: unrecognized target" +#endif + +#include "phoenix.hpp" +using namespace nall; + +namespace phoenix { + #include "core/core.cpp" +} + +#endif diff --git a/kaijuu/phoenix/phoenix.hpp b/kaijuu/phoenix/phoenix.hpp new file mode 100644 index 00000000..8a6129c4 --- /dev/null +++ b/kaijuu/phoenix/phoenix.hpp @@ -0,0 +1,19 @@ +#ifndef PHOENIX_HPP +#define PHOENIX_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace phoenix { + #include "core/core.hpp" +} + +#endif diff --git a/kaijuu/phoenix/qt/action/action.cpp b/kaijuu/phoenix/qt/action/action.cpp new file mode 100644 index 00000000..62efaa2a --- /dev/null +++ b/kaijuu/phoenix/qt/action/action.cpp @@ -0,0 +1,49 @@ +void pAction::setEnabled(bool enabled) { + if(dynamic_cast(&action)) { + ((Menu&)action).p.qtMenu->setEnabled(enabled); + } else if(dynamic_cast(&action)) { + ((Separator&)action).p.qtAction->setEnabled(enabled); + } else if(dynamic_cast(&action)) { + ((Item&)action).p.qtAction->setEnabled(enabled); + } else if(dynamic_cast(&action)) { + ((CheckItem&)action).p.qtAction->setEnabled(enabled); + } else if(dynamic_cast(&action)) { + ((RadioItem&)action).p.qtAction->setEnabled(enabled); + } +} + +void pAction::setFont(const string &font) { + QFont qtFont = pFont::create(font); + + if(dynamic_cast(&action)) { + ((Menu&)action).p.setFont(font); + } else if(dynamic_cast(&action)) { + ((Separator&)action).p.qtAction->setFont(qtFont); + } else if(dynamic_cast(&action)) { + ((Item&)action).p.qtAction->setFont(qtFont); + } else if(dynamic_cast(&action)) { + ((CheckItem&)action).p.qtAction->setFont(qtFont); + } else if(dynamic_cast(&action)) { + ((RadioItem&)action).p.qtAction->setFont(qtFont); + } +} + +void pAction::setVisible(bool visible) { + if(dynamic_cast(&action)) { + ((Menu&)action).p.qtMenu->menuAction()->setVisible(visible); + } else if(dynamic_cast(&action)) { + ((Separator&)action).p.qtAction->setVisible(visible); + } else if(dynamic_cast(&action)) { + ((Item&)action).p.qtAction->setVisible(visible); + } else if(dynamic_cast(&action)) { + ((CheckItem&)action).p.qtAction->setVisible(visible); + } else if(dynamic_cast(&action)) { + ((RadioItem&)action).p.qtAction->setVisible(visible); + } +} + +void pAction::constructor() { +} + +void pAction::destructor() { +} diff --git a/kaijuu/phoenix/qt/action/check-item.cpp b/kaijuu/phoenix/qt/action/check-item.cpp new file mode 100644 index 00000000..ef451e73 --- /dev/null +++ b/kaijuu/phoenix/qt/action/check-item.cpp @@ -0,0 +1,27 @@ +bool pCheckItem::checked() { + return qtAction->isChecked(); +} + +void pCheckItem::setChecked(bool checked) { + qtAction->setChecked(checked); +} + +void pCheckItem::setText(const string &text) { + qtAction->setText(QString::fromUtf8(text)); +} + +void pCheckItem::constructor() { + qtAction = new QAction(0); + qtAction->setCheckable(true); + connect(qtAction, SIGNAL(triggered()), SLOT(onToggle())); +} + +void pCheckItem::destructor() { + if(action.state.menu) action.state.menu->remove(checkItem); + delete qtAction; +} + +void pCheckItem::onToggle() { + checkItem.state.checked = checked(); + if(checkItem.onToggle) checkItem.onToggle(); +} diff --git a/kaijuu/phoenix/qt/action/item.cpp b/kaijuu/phoenix/qt/action/item.cpp new file mode 100644 index 00000000..7f142289 --- /dev/null +++ b/kaijuu/phoenix/qt/action/item.cpp @@ -0,0 +1,21 @@ +void pItem::setImage(const image &image) { + qtAction->setIcon(CreateIcon(image)); +} + +void pItem::setText(const string &text) { + qtAction->setText(QString::fromUtf8(text)); +} + +void pItem::constructor() { + qtAction = new QAction(0); + connect(qtAction, SIGNAL(triggered()), SLOT(onActivate())); +} + +void pItem::destructor() { + if(action.state.menu) action.state.menu->remove(item); + delete qtAction; +} + +void pItem::onActivate() { + if(item.onActivate) item.onActivate(); +} diff --git a/kaijuu/phoenix/qt/action/menu.cpp b/kaijuu/phoenix/qt/action/menu.cpp new file mode 100644 index 00000000..43d89a1e --- /dev/null +++ b/kaijuu/phoenix/qt/action/menu.cpp @@ -0,0 +1,51 @@ +void pMenu::append(Action &action) { + if(dynamic_cast(&action)) { + qtMenu->addMenu(((Menu&)action).p.qtMenu); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((Separator&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((Item&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((CheckItem&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((RadioItem&)action).p.qtAction); + } +} + +void pMenu::remove(Action &action) { + if(dynamic_cast(&action)) { + //QMenu::removeMenu() does not exist + qtMenu->clear(); + for(auto &action : menu.state.action) append(action); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((Separator&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((Item&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((CheckItem&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((CheckItem&)action).p.qtAction); + } +} + +void pMenu::setFont(const string &font) { + qtMenu->setFont(pFont::create(font)); + for(auto &item : menu.state.action) item.p.setFont(font); +} + +void pMenu::setImage(const image &image) { + qtMenu->setIcon(CreateIcon(image)); +} + +void pMenu::setText(const string &text) { + qtMenu->setTitle(QString::fromUtf8(text)); +} + +void pMenu::constructor() { + qtMenu = new QMenu; +} + +void pMenu::destructor() { + if(action.state.menu) action.state.menu->remove(menu); + delete qtMenu; +} diff --git a/kaijuu/phoenix/qt/action/radio-item.cpp b/kaijuu/phoenix/qt/action/radio-item.cpp new file mode 100644 index 00000000..66cf6c6a --- /dev/null +++ b/kaijuu/phoenix/qt/action/radio-item.cpp @@ -0,0 +1,41 @@ +bool pRadioItem::checked() { + return qtAction->isChecked(); +} + +void pRadioItem::setChecked() { + locked = true; + for(auto &item : radioItem.state.group) { + bool checkState = item.p.qtAction == qtAction; + item.state.checked = checkState; + item.p.qtAction->setChecked(checkState); + } + locked = false; +} + +void pRadioItem::setGroup(const set &group) { +} + +void pRadioItem::setText(const string &text) { + qtAction->setText(QString::fromUtf8(text)); +} + +void pRadioItem::constructor() { + qtAction = new QAction(0); + qtGroup = new QActionGroup(0); + qtAction->setCheckable(true); + qtAction->setActionGroup(qtGroup); + qtAction->setChecked(true); + connect(qtAction, SIGNAL(triggered()), SLOT(onActivate())); +} + +void pRadioItem::destructor() { + if(action.state.menu) action.state.menu->remove(radioItem); + delete qtAction; +} + +void pRadioItem::onActivate() { + if(radioItem.state.checked == false) { + setChecked(); + if(locked == false && radioItem.onActivate) radioItem.onActivate(); + } +} diff --git a/kaijuu/phoenix/qt/action/separator.cpp b/kaijuu/phoenix/qt/action/separator.cpp new file mode 100644 index 00000000..95e66b6c --- /dev/null +++ b/kaijuu/phoenix/qt/action/separator.cpp @@ -0,0 +1,9 @@ +void pSeparator::constructor() { + qtAction = new QAction(0); + qtAction->setSeparator(true); +} + +void pSeparator::destructor() { + if(action.state.menu) action.state.menu->remove(separator); + delete qtAction; +} diff --git a/kaijuu/phoenix/qt/desktop.cpp b/kaijuu/phoenix/qt/desktop.cpp new file mode 100644 index 00000000..554106b5 --- /dev/null +++ b/kaijuu/phoenix/qt/desktop.cpp @@ -0,0 +1,9 @@ +Size pDesktop::size() { + QRect rect = QApplication::desktop()->screenGeometry(); + return { rect.width(), rect.height() }; +} + +Geometry pDesktop::workspace() { + QRect rect = QApplication::desktop()->availableGeometry(); + return { rect.x(), rect.y(), rect.width(), rect.height() }; +} diff --git a/kaijuu/phoenix/qt/dialog-window.cpp b/kaijuu/phoenix/qt/dialog-window.cpp new file mode 100644 index 00000000..680a6e2e --- /dev/null +++ b/kaijuu/phoenix/qt/dialog-window.cpp @@ -0,0 +1,57 @@ +string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) { + string filterList; + for(auto &item : filter) { + filterList.append(item); + filterList.append(";;"); + } + filterList.rtrim<1>(";;"); + + //convert filter list from phoenix to Qt format, example: + //"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)" + signed parenthesis = 0; + for(auto &n : filterList) { + if(n == '(') parenthesis++; + if(n == ')') parenthesis--; + if(n == ',' && parenthesis) n = ' '; + } + + QString filename = QFileDialog::getOpenFileName( + &parent != &Window::none() ? parent.p.qtWindow : nullptr, "Open File", + QString::fromUtf8(path), QString::fromUtf8(filterList) + ); + return filename.toUtf8().constData(); +} + +string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) { + string filterList; + for(auto &item : filter) { + filterList.append(item); + filterList.append(";;"); + } + filterList.rtrim<1>(";;"); + + //convert filter list from phoenix to Qt format, example: + //"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)" + signed parenthesis = 0; + for(auto &n : filterList) { + if(n == '(') parenthesis++; + if(n == ')') parenthesis--; + if(n == ',' && parenthesis) n = ' '; + } + + QString filename = QFileDialog::getSaveFileName( + &parent != &Window::none() ? parent.p.qtWindow : nullptr, "Save File", + QString::fromUtf8(path), QString::fromUtf8(filterList) + ); + return filename.toUtf8().constData(); +} + +string pDialogWindow::folderSelect(Window &parent, const string &path) { + QString directory = QFileDialog::getExistingDirectory( + &parent != &Window::none() ? parent.p.qtWindow : nullptr, "Select Directory", + QString::fromUtf8(path), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks + ); + string name = directory.toUtf8().constData(); + if(name != "" && name.endswith("/") == false) name.append("/"); + return name; +} diff --git a/kaijuu/phoenix/qt/font.cpp b/kaijuu/phoenix/qt/font.cpp new file mode 100644 index 00000000..bb3261cd --- /dev/null +++ b/kaijuu/phoenix/qt/font.cpp @@ -0,0 +1,40 @@ +Geometry pFont::geometry(const string &description, const string &text) { + return pFont::geometry(pFont::create(description), text); +} + +QFont pFont::create(const string &description) { + lstring part; + part.split(",", description); + for(auto &item : part) item.trim(" "); + + string family = "Sans"; + unsigned size = 8u; + bool bold = false; + bool italic = false; + + if(part[0] != "") family = part[0]; + if(part.size() >= 2) size = decimal(part[1]); + if(part.size() >= 3) bold = part[2].position("Bold"); + if(part.size() >= 3) italic = part[2].position("Italic"); + + QFont qtFont; + qtFont.setFamily(family); + qtFont.setPointSize(size); + if(bold) qtFont.setBold(true); + if(italic) qtFont.setItalic(true); + return qtFont; +} + +Geometry pFont::geometry(const QFont &qtFont, const string &text) { + QFontMetrics metrics(qtFont); + + lstring lines; + lines.split("\n", text); + + unsigned maxWidth = 0; + for(auto &line : lines) { + maxWidth = max(maxWidth, metrics.width(line)); + } + + return { 0, 0, maxWidth, metrics.height() * lines.size() }; +} diff --git a/kaijuu/phoenix/qt/keyboard.cpp b/kaijuu/phoenix/qt/keyboard.cpp new file mode 100644 index 00000000..5b346406 --- /dev/null +++ b/kaijuu/phoenix/qt/keyboard.cpp @@ -0,0 +1,142 @@ +void pKeyboard::initialize() { + auto append = [](Keyboard::Scancode scancode, unsigned keysym) { + settings->keymap.insert(scancode, XKeysymToKeycode(pOS::display, keysym)); + }; + + append(Keyboard::Scancode::Escape, XK_Escape); + append(Keyboard::Scancode::F1, XK_F1); + append(Keyboard::Scancode::F2, XK_F2); + append(Keyboard::Scancode::F3, XK_F3); + append(Keyboard::Scancode::F4, XK_F4); + append(Keyboard::Scancode::F5, XK_F5); + append(Keyboard::Scancode::F6, XK_F6); + append(Keyboard::Scancode::F7, XK_F7); + append(Keyboard::Scancode::F8, XK_F8); + append(Keyboard::Scancode::F9, XK_F9); + append(Keyboard::Scancode::F10, XK_F10); + append(Keyboard::Scancode::F11, XK_F11); + append(Keyboard::Scancode::F12, XK_F12); + + append(Keyboard::Scancode::PrintScreen, XK_Print); + append(Keyboard::Scancode::ScrollLock, XK_Scroll_Lock); + append(Keyboard::Scancode::Pause, XK_Pause); + + append(Keyboard::Scancode::Insert, XK_Insert); + append(Keyboard::Scancode::Delete, XK_Delete); + append(Keyboard::Scancode::Home, XK_Home); + append(Keyboard::Scancode::End, XK_End); + append(Keyboard::Scancode::PageUp, XK_Prior); + append(Keyboard::Scancode::PageDown, XK_Next); + + append(Keyboard::Scancode::Up, XK_Up); + append(Keyboard::Scancode::Down, XK_Down); + append(Keyboard::Scancode::Left, XK_Left); + append(Keyboard::Scancode::Right, XK_Right); + + append(Keyboard::Scancode::Grave, XK_asciitilde); + append(Keyboard::Scancode::Number1, XK_1); + append(Keyboard::Scancode::Number2, XK_2); + append(Keyboard::Scancode::Number3, XK_3); + append(Keyboard::Scancode::Number4, XK_4); + append(Keyboard::Scancode::Number5, XK_5); + append(Keyboard::Scancode::Number6, XK_6); + append(Keyboard::Scancode::Number7, XK_7); + append(Keyboard::Scancode::Number8, XK_8); + append(Keyboard::Scancode::Number9, XK_9); + append(Keyboard::Scancode::Number0, XK_0); + append(Keyboard::Scancode::Minus, XK_minus); + append(Keyboard::Scancode::Equal, XK_equal); + append(Keyboard::Scancode::Backspace, XK_BackSpace); + + append(Keyboard::Scancode::BracketLeft, XK_bracketleft); + append(Keyboard::Scancode::BracketRight, XK_bracketright); + append(Keyboard::Scancode::Backslash, XK_backslash); + append(Keyboard::Scancode::Semicolon, XK_semicolon); + append(Keyboard::Scancode::Apostrophe, XK_apostrophe); + append(Keyboard::Scancode::Comma, XK_comma); + append(Keyboard::Scancode::Period, XK_period); + append(Keyboard::Scancode::Slash, XK_slash); + + append(Keyboard::Scancode::Tab, XK_Tab); + append(Keyboard::Scancode::CapsLock, XK_Caps_Lock); + append(Keyboard::Scancode::Return, XK_Return); + append(Keyboard::Scancode::ShiftLeft, XK_Shift_L); + append(Keyboard::Scancode::ShiftRight, XK_Shift_R); + append(Keyboard::Scancode::ControlLeft, XK_Control_L); + append(Keyboard::Scancode::ControlRight, XK_Control_R); + append(Keyboard::Scancode::SuperLeft, XK_Super_L); + append(Keyboard::Scancode::SuperRight, XK_Super_R); + append(Keyboard::Scancode::AltLeft, XK_Alt_L); + append(Keyboard::Scancode::AltRight, XK_Alt_R); + append(Keyboard::Scancode::Space, XK_space); + append(Keyboard::Scancode::Menu, XK_Menu); + + append(Keyboard::Scancode::A, XK_A); + append(Keyboard::Scancode::B, XK_B); + append(Keyboard::Scancode::C, XK_C); + append(Keyboard::Scancode::D, XK_D); + append(Keyboard::Scancode::E, XK_E); + append(Keyboard::Scancode::F, XK_F); + append(Keyboard::Scancode::G, XK_G); + append(Keyboard::Scancode::H, XK_H); + append(Keyboard::Scancode::I, XK_I); + append(Keyboard::Scancode::J, XK_J); + append(Keyboard::Scancode::K, XK_K); + append(Keyboard::Scancode::L, XK_L); + append(Keyboard::Scancode::M, XK_M); + append(Keyboard::Scancode::N, XK_N); + append(Keyboard::Scancode::O, XK_O); + append(Keyboard::Scancode::P, XK_P); + append(Keyboard::Scancode::Q, XK_Q); + append(Keyboard::Scancode::R, XK_R); + append(Keyboard::Scancode::S, XK_S); + append(Keyboard::Scancode::T, XK_T); + append(Keyboard::Scancode::U, XK_U); + append(Keyboard::Scancode::V, XK_V); + append(Keyboard::Scancode::W, XK_W); + append(Keyboard::Scancode::X, XK_X); + append(Keyboard::Scancode::Y, XK_Y); + append(Keyboard::Scancode::Z, XK_Z); + + append(Keyboard::Scancode::NumLock, XK_Num_Lock); + append(Keyboard::Scancode::Divide, XK_KP_Divide); + append(Keyboard::Scancode::Multiply, XK_KP_Multiply); + append(Keyboard::Scancode::Subtract, XK_KP_Subtract); + append(Keyboard::Scancode::Add, XK_KP_Add); + append(Keyboard::Scancode::Enter, XK_KP_Enter); + append(Keyboard::Scancode::Point, XK_KP_Decimal); + + append(Keyboard::Scancode::Keypad1, XK_KP_1); + append(Keyboard::Scancode::Keypad2, XK_KP_2); + append(Keyboard::Scancode::Keypad3, XK_KP_3); + append(Keyboard::Scancode::Keypad4, XK_KP_4); + append(Keyboard::Scancode::Keypad5, XK_KP_5); + append(Keyboard::Scancode::Keypad6, XK_KP_6); + append(Keyboard::Scancode::Keypad7, XK_KP_7); + append(Keyboard::Scancode::Keypad8, XK_KP_8); + append(Keyboard::Scancode::Keypad9, XK_KP_9); + append(Keyboard::Scancode::Keypad0, XK_KP_0); +} + +bool pKeyboard::pressed(Keyboard::Scancode scancode) { + char state[256]; + XQueryKeymap(pOS::display, state); + unsigned id = settings->keymap.lhs[scancode]; + return state[id >> 3] & (1 << (id & 7)); +} + +vector pKeyboard::state() { + vector output; + output.resize((unsigned)Keyboard::Scancode::Limit); + for(auto &n : output) n = false; + + char state[256]; + XQueryKeymap(pOS::display, state); + for(auto &n : settings->keymap.rhs) { + if(state[n.name >> 3] & (1 << (n.name & 7))) { + output[(unsigned)n.data] = true; + } + } + + return output; +} diff --git a/kaijuu/phoenix/qt/message-window.cpp b/kaijuu/phoenix/qt/message-window.cpp new file mode 100644 index 00000000..7bceba0f --- /dev/null +++ b/kaijuu/phoenix/qt/message-window.cpp @@ -0,0 +1,47 @@ +static QMessageBox::StandardButtons MessageWindow_buttons(MessageWindow::Buttons buttons) { + QMessageBox::StandardButtons standardButtons = QMessageBox::NoButton; + if(buttons == MessageWindow::Buttons::Ok) standardButtons = QMessageBox::Ok; + if(buttons == MessageWindow::Buttons::OkCancel) standardButtons = QMessageBox::Ok | QMessageBox::Cancel; + if(buttons == MessageWindow::Buttons::YesNo) standardButtons = QMessageBox::Yes | QMessageBox::No; + return standardButtons; +} + +static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, QMessageBox::StandardButton response) { + if(response == QMessageBox::Ok) return MessageWindow::Response::Ok; + if(response == QMessageBox::Cancel) return MessageWindow::Response::Cancel; + if(response == QMessageBox::Yes) return MessageWindow::Response::Yes; + if(response == QMessageBox::No) return MessageWindow::Response::No; + + //MessageWindow was closed via window manager, rather than by a button; assume a cancel/no response + if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel; + if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow_response( + buttons, QMessageBox::information(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ", + QString::fromUtf8(text), MessageWindow_buttons(buttons)) + ); +} + +MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow_response( + buttons, QMessageBox::question(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ", + QString::fromUtf8(text), MessageWindow_buttons(buttons)) + ); +} + +MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow_response( + buttons, QMessageBox::warning(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ", + QString::fromUtf8(text), MessageWindow_buttons(buttons)) + ); +} + +MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow_response( + buttons, QMessageBox::critical(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ", + QString::fromUtf8(text), MessageWindow_buttons(buttons)) + ); +} diff --git a/kaijuu/phoenix/qt/mouse.cpp b/kaijuu/phoenix/qt/mouse.cpp new file mode 100644 index 00000000..4ea06cc9 --- /dev/null +++ b/kaijuu/phoenix/qt/mouse.cpp @@ -0,0 +1,14 @@ +Position pMouse::position() { + QPoint point = QCursor::pos(); + return { point.x(), point.y() }; +} + +bool pMouse::pressed(Mouse::Button button) { + Qt::MouseButtons buttons = QApplication::mouseButtons(); + switch(button) { + case Mouse::Button::Left: return buttons & Qt::LeftButton; + case Mouse::Button::Middle: return buttons & Qt::MidButton; + case Mouse::Button::Right: return buttons & Qt::RightButton; + } + return false; +} diff --git a/kaijuu/phoenix/qt/platform.cpp b/kaijuu/phoenix/qt/platform.cpp new file mode 100644 index 00000000..86f659c8 --- /dev/null +++ b/kaijuu/phoenix/qt/platform.cpp @@ -0,0 +1,91 @@ +//Qt 4.8.0 and earlier improperly define the QLOCATION macro +//in C++11, it is detected as a malformed user-defined literal +//below is a workaround to fix compilation errors caused by this +#undef QLOCATION +#define QLOCATION "\0" __FILE__ ":" QTOSTRING(__LINE__) + +#include "platform.moc.hpp" +#include "platform.moc" +#include "utility.cpp" +#include "settings.cpp" + +#include "desktop.cpp" +#include "keyboard.cpp" +#include "mouse.cpp" +#include "dialog-window.cpp" +#include "message-window.cpp" + +#include "font.cpp" +#include "timer.cpp" +#include "window.cpp" + +#include "action/action.cpp" +#include "action/menu.cpp" +#include "action/separator.cpp" +#include "action/item.cpp" +#include "action/check-item.cpp" +#include "action/radio-item.cpp" + +#include "widget/widget.cpp" +#include "widget/button.cpp" +#include "widget/canvas.cpp" +#include "widget/check-box.cpp" +#include "widget/combo-box.cpp" +#include "widget/hex-edit.cpp" +#include "widget/horizontal-scroll-bar.cpp" +#include "widget/horizontal-slider.cpp" +#include "widget/label.cpp" +#include "widget/line-edit.cpp" +#include "widget/list-view.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-box.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +XlibDisplay* pOS::display = 0; + +void pOS::main() { + QApplication::exec(); +} + +bool pOS::pendingEvents() { + return QApplication::hasPendingEvents(); +} + +void pOS::processEvents() { + while(pendingEvents()) QApplication::processEvents(); +} + +void pOS::quit() { + QApplication::quit(); + //note: QApplication cannot be deleted; or libQtGui will crash + qtApplication = 0; +} + +void pOS::syncX() { + for(unsigned n = 0; n < 8; n++) { + QApplication::syncX(); + OS::processEvents(); + usleep(2000); + } +} + +void pOS::initialize() { + display = XOpenDisplay(0); + + settings = new Settings; + settings->load(); + + static int argc = 1; + static char *argv[2]; + argv[0] = new char[8]; + argv[1] = 0; + strcpy(argv[0], "phoenix"); + char **argvp = argv; + + qtApplication = new QApplication(argc, argvp); + + pKeyboard::initialize(); +} diff --git a/kaijuu/phoenix/qt/platform.moc b/kaijuu/phoenix/qt/platform.moc new file mode 100644 index 00000000..3b2db923 --- /dev/null +++ b/kaijuu/phoenix/qt/platform.moc @@ -0,0 +1,1105 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'platform.moc.hpp' +** +** Created: Sun Jul 22 02:20:29 2012 +** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'platform.moc.hpp' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 62 +#error "This file was generated using the moc from 4.6.3. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +static const uint qt_meta_data_pTimer[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 8, 7, 7, 7, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pTimer[] = { + "pTimer\0\0onTimeout()\0" +}; + +const QMetaObject pTimer::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pTimer, + qt_meta_data_pTimer, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pTimer::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pTimer::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pTimer::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pTimer)) + return static_cast(const_cast< pTimer*>(this)); + if (!strcmp(_clname, "pObject")) + return static_cast< pObject*>(const_cast< pTimer*>(this)); + return QObject::qt_metacast(_clname); +} + +int pTimer::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onTimeout(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pWindow[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 0, 0, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + 0 // eod +}; + +static const char qt_meta_stringdata_pWindow[] = { + "pWindow\0" +}; + +const QMetaObject pWindow::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pWindow, + qt_meta_data_pWindow, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pWindow::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pWindow::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pWindow::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pWindow)) + return static_cast(const_cast< pWindow*>(this)); + if (!strcmp(_clname, "pObject")) + return static_cast< pObject*>(const_cast< pWindow*>(this)); + return QObject::qt_metacast(_clname); +} + +int pWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + return _id; +} +static const uint qt_meta_data_pItem[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 7, 6, 6, 6, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pItem[] = { + "pItem\0\0onActivate()\0" +}; + +const QMetaObject pItem::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pItem, + qt_meta_data_pItem, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pItem::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pItem::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pItem::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pItem)) + return static_cast(const_cast< pItem*>(this)); + if (!strcmp(_clname, "pAction")) + return static_cast< pAction*>(const_cast< pItem*>(this)); + return QObject::qt_metacast(_clname); +} + +int pItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onActivate(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pCheckItem[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 12, 11, 11, 11, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pCheckItem[] = { + "pCheckItem\0\0onToggle()\0" +}; + +const QMetaObject pCheckItem::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pCheckItem, + qt_meta_data_pCheckItem, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pCheckItem::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pCheckItem::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pCheckItem::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pCheckItem)) + return static_cast(const_cast< pCheckItem*>(this)); + if (!strcmp(_clname, "pAction")) + return static_cast< pAction*>(const_cast< pCheckItem*>(this)); + return QObject::qt_metacast(_clname); +} + +int pCheckItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onToggle(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pRadioItem[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 12, 11, 11, 11, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pRadioItem[] = { + "pRadioItem\0\0onActivate()\0" +}; + +const QMetaObject pRadioItem::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pRadioItem, + qt_meta_data_pRadioItem, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pRadioItem::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pRadioItem::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pRadioItem::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pRadioItem)) + return static_cast(const_cast< pRadioItem*>(this)); + if (!strcmp(_clname, "pAction")) + return static_cast< pAction*>(const_cast< pRadioItem*>(this)); + return QObject::qt_metacast(_clname); +} + +int pRadioItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onActivate(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pButton[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 9, 8, 8, 8, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pButton[] = { + "pButton\0\0onActivate()\0" +}; + +const QMetaObject pButton::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pButton, + qt_meta_data_pButton, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pButton::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pButton::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pButton::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pButton)) + return static_cast(const_cast< pButton*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pButton*>(this)); + return QObject::qt_metacast(_clname); +} + +int pButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onActivate(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pCanvas[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 0, 0, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + 0 // eod +}; + +static const char qt_meta_stringdata_pCanvas[] = { + "pCanvas\0" +}; + +const QMetaObject pCanvas::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pCanvas, + qt_meta_data_pCanvas, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pCanvas::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pCanvas::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pCanvas::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pCanvas)) + return static_cast(const_cast< pCanvas*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pCanvas*>(this)); + return QObject::qt_metacast(_clname); +} + +int pCanvas::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + return _id; +} +static const uint qt_meta_data_pCheckBox[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pCheckBox[] = { + "pCheckBox\0\0onToggle()\0" +}; + +const QMetaObject pCheckBox::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pCheckBox, + qt_meta_data_pCheckBox, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pCheckBox::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pCheckBox::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pCheckBox::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pCheckBox)) + return static_cast(const_cast< pCheckBox*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pCheckBox*>(this)); + return QObject::qt_metacast(_clname); +} + +int pCheckBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onToggle(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pComboBox[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pComboBox[] = { + "pComboBox\0\0onChange()\0" +}; + +const QMetaObject pComboBox::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pComboBox, + qt_meta_data_pComboBox, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pComboBox::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pComboBox::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pComboBox::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pComboBox)) + return static_cast(const_cast< pComboBox*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pComboBox*>(this)); + return QObject::qt_metacast(_clname); +} + +int pComboBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pHexEdit[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 10, 9, 9, 9, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pHexEdit[] = { + "pHexEdit\0\0onScroll()\0" +}; + +const QMetaObject pHexEdit::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pHexEdit, + qt_meta_data_pHexEdit, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pHexEdit::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pHexEdit::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pHexEdit::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pHexEdit)) + return static_cast(const_cast< pHexEdit*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pHexEdit*>(this)); + return QObject::qt_metacast(_clname); +} + +int pHexEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onScroll(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pHorizontalScrollBar[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 22, 21, 21, 21, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pHorizontalScrollBar[] = { + "pHorizontalScrollBar\0\0onChange()\0" +}; + +const QMetaObject pHorizontalScrollBar::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pHorizontalScrollBar, + qt_meta_data_pHorizontalScrollBar, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pHorizontalScrollBar::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pHorizontalScrollBar::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pHorizontalScrollBar::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pHorizontalScrollBar)) + return static_cast(const_cast< pHorizontalScrollBar*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pHorizontalScrollBar*>(this)); + return QObject::qt_metacast(_clname); +} + +int pHorizontalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pHorizontalSlider[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 19, 18, 18, 18, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pHorizontalSlider[] = { + "pHorizontalSlider\0\0onChange()\0" +}; + +const QMetaObject pHorizontalSlider::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pHorizontalSlider, + qt_meta_data_pHorizontalSlider, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pHorizontalSlider::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pHorizontalSlider::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pHorizontalSlider::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pHorizontalSlider)) + return static_cast(const_cast< pHorizontalSlider*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pHorizontalSlider*>(this)); + return QObject::qt_metacast(_clname); +} + +int pHorizontalSlider::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pLineEdit[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 2, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + 24, 10, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pLineEdit[] = { + "pLineEdit\0\0onActivate()\0onChange()\0" +}; + +const QMetaObject pLineEdit::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pLineEdit, + qt_meta_data_pLineEdit, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pLineEdit::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pLineEdit::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pLineEdit::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pLineEdit)) + return static_cast(const_cast< pLineEdit*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pLineEdit*>(this)); + return QObject::qt_metacast(_clname); +} + +int pLineEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onActivate(); break; + case 1: onChange(); break; + default: ; + } + _id -= 2; + } + return _id; +} +static const uint qt_meta_data_pListView[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 3, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + 29, 24, 10, 10, 0x0a, + 56, 24, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pListView[] = { + "pListView\0\0onActivate()\0item\0" + "onChange(QTreeWidgetItem*)\0" + "onToggle(QTreeWidgetItem*)\0" +}; + +const QMetaObject pListView::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pListView, + qt_meta_data_pListView, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pListView::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pListView::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pListView::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pListView)) + return static_cast(const_cast< pListView*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pListView*>(this)); + return QObject::qt_metacast(_clname); +} + +int pListView::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onActivate(); break; + case 1: onChange((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break; + case 2: onToggle((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break; + default: ; + } + _id -= 3; + } + return _id; +} +static const uint qt_meta_data_pRadioBox[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pRadioBox[] = { + "pRadioBox\0\0onActivate()\0" +}; + +const QMetaObject pRadioBox::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pRadioBox, + qt_meta_data_pRadioBox, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pRadioBox::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pRadioBox::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pRadioBox::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pRadioBox)) + return static_cast(const_cast< pRadioBox*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pRadioBox*>(this)); + return QObject::qt_metacast(_clname); +} + +int pRadioBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onActivate(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pTextEdit[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pTextEdit[] = { + "pTextEdit\0\0onChange()\0" +}; + +const QMetaObject pTextEdit::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pTextEdit, + qt_meta_data_pTextEdit, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pTextEdit::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pTextEdit::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pTextEdit::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pTextEdit)) + return static_cast(const_cast< pTextEdit*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pTextEdit*>(this)); + return QObject::qt_metacast(_clname); +} + +int pTextEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pVerticalScrollBar[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 20, 19, 19, 19, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pVerticalScrollBar[] = { + "pVerticalScrollBar\0\0onChange()\0" +}; + +const QMetaObject pVerticalScrollBar::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pVerticalScrollBar, + qt_meta_data_pVerticalScrollBar, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pVerticalScrollBar::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pVerticalScrollBar::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pVerticalScrollBar::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pVerticalScrollBar)) + return static_cast(const_cast< pVerticalScrollBar*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pVerticalScrollBar*>(this)); + return QObject::qt_metacast(_clname); +} + +int pVerticalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pVerticalSlider[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 17, 16, 16, 16, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pVerticalSlider[] = { + "pVerticalSlider\0\0onChange()\0" +}; + +const QMetaObject pVerticalSlider::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pVerticalSlider, + qt_meta_data_pVerticalSlider, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pVerticalSlider::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pVerticalSlider::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pVerticalSlider::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pVerticalSlider)) + return static_cast(const_cast< pVerticalSlider*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pVerticalSlider*>(this)); + return QObject::qt_metacast(_clname); +} + +int pVerticalSlider::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +QT_END_MOC_NAMESPACE diff --git a/kaijuu/phoenix/qt/platform.moc.hpp b/kaijuu/phoenix/qt/platform.moc.hpp new file mode 100644 index 00000000..9e75fdc8 --- /dev/null +++ b/kaijuu/phoenix/qt/platform.moc.hpp @@ -0,0 +1,633 @@ +static QApplication *qtApplication = nullptr; + +struct Settings : public configuration { + bidirectional_map keymap; + + unsigned frameGeometryX; + unsigned frameGeometryY; + unsigned frameGeometryWidth; + unsigned frameGeometryHeight; + unsigned menuGeometryHeight; + unsigned statusGeometryHeight; + + void load(); + void save(); + Settings(); +}; + +struct pWindow; +struct pMenu; +struct pLayout; +struct pWidget; + +struct pFont { + static Geometry geometry(const string &description, const string &text); + + static QFont create(const string &description); + static Geometry geometry(const QFont &qtFont, const string &text); +}; + +struct pDesktop { + static Size size(); + static Geometry workspace(); +}; + +struct pKeyboard { + static bool pressed(Keyboard::Scancode scancode); + static vector state(); + + static void initialize(); +}; + +struct pMouse { + static Position position(); + static bool pressed(Mouse::Button button); +}; + +struct pDialogWindow { + static string fileOpen(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); +}; + +struct pMessageWindow { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + +struct pObject { + Object &object; + bool locked; + + pObject(Object &object) : object(object), locked(false) {} + virtual ~pObject() {} + void constructor() {} + void destructor() {} +}; + +struct pOS : public pObject { + static XlibDisplay *display; + + static void main(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + static void initialize(); + static void syncX(); +}; + +struct pTimer : public QObject, public pObject { + Q_OBJECT + +public: + Timer &timer; + QTimer *qtTimer; + + void setEnabled(bool enabled); + void setInterval(unsigned milliseconds); + + pTimer(Timer &timer) : pObject(timer), timer(timer) {} + void constructor(); + void destructor(); + +public slots: + void onTimeout(); +}; + +struct pWindow : public QObject, public pObject { + Q_OBJECT + +public: + Window &window; + struct QtWindow : public QWidget { + pWindow &self; + void closeEvent(QCloseEvent*); + void keyPressEvent(QKeyEvent*); + void keyReleaseEvent(QKeyEvent*); + void moveEvent(QMoveEvent*); + void resizeEvent(QResizeEvent*); + QSize sizeHint() const; + QtWindow(pWindow &self) : self(self) {} + } *qtWindow; + QVBoxLayout *qtLayout; + QMenuBar *qtMenu; + QStatusBar *qtStatus; + QWidget *qtContainer; + + static Window& none(); + + void append(Layout &layout); + void append(Menu &menu); + void append(Widget &widget); + Color backgroundColor(); + Geometry frameMargin(); + bool focused(); + Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); + void setBackgroundColor(const Color &color); + void setFocused(); + void setFullScreen(bool fullScreen); + void setGeometry(const Geometry &geometry); + void setMenuFont(const string &font); + void setMenuVisible(bool visible); + void setModal(bool modal); + void setResizable(bool resizable); + void setStatusFont(const string &font); + void setStatusText(const string &text); + void setStatusVisible(bool visible); + void setTitle(const string &text); + void setVisible(bool visible); + void setWidgetFont(const string &font); + + pWindow(Window &window) : pObject(window), window(window) {} + void constructor(); + void destructor(); + void updateFrameGeometry(); +}; + +struct pAction : public pObject { + Action &action; + + void setEnabled(bool enabled); + void setFont(const string &font); + void setVisible(bool visible); + + pAction(Action &action) : pObject(action), action(action) {} + void constructor(); + void destructor(); +}; + +struct pMenu : public pAction { + Menu &menu; + QMenu *qtMenu; + + void append(Action &action); + void remove(Action &action); + void setFont(const string &font); + void setImage(const image &image); + void setText(const string &text); + + pMenu(Menu &menu) : pAction(menu), menu(menu) {} + void constructor(); + void destructor(); +}; + +struct pSeparator : public pAction { + Separator &separator; + QAction *qtAction; + + pSeparator(Separator &separator) : pAction(separator), separator(separator) {} + void constructor(); + void destructor(); +}; + +struct pItem : public QObject, public pAction { + Q_OBJECT + +public: + Item &item; + QAction *qtAction; + + void setImage(const image &image); + void setText(const string &text); + + pItem(Item &item) : pAction(item), item(item) {} + void constructor(); + void destructor(); + +public slots: + void onActivate(); +}; + +struct pCheckItem : public QObject, public pAction { + Q_OBJECT + +public: + CheckItem &checkItem; + QAction *qtAction; + + bool checked(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} + void constructor(); + void destructor(); + +public slots: + void onToggle(); +}; + +struct pRadioItem : public QObject, public pAction { + Q_OBJECT + +public: + RadioItem &radioItem; + QAction *qtAction; + QActionGroup *qtGroup; + + bool checked(); + void setChecked(); + void setGroup(const set &group); + void setText(const string &text); + + pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} + void constructor(); + void destructor(); + +public slots: + void onActivate(); +}; + +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} + + void constructor() {} + void destructor() {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} + + void constructor() {} + void destructor() {} +}; + +struct pWidget : public pSizable { + Widget &widget; + QWidget *qtWidget; + + virtual Geometry minimumGeometry(); + void setEnabled(bool enabled); + void setFocused(); + void setFont(const string &font); + virtual void setGeometry(const Geometry &geometry); + void setVisible(bool visible); + + pWidget(Widget &widget) : pSizable(widget), widget(widget) {} + void constructor(); + void synchronizeState(); + void destructor(); + virtual void orphan(); +}; + +struct pButton : public QObject, public pWidget { + Q_OBJECT + +public: + Button &button; + QToolButton *qtButton; + + Geometry minimumGeometry(); + void setImage(const image &image, Orientation orientation); + void setText(const string &text); + + pButton(Button &button) : pWidget(button), button(button) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onActivate(); +}; + +struct pCanvas : public QObject, public pWidget { + Q_OBJECT + +public: + Canvas &canvas; + QImage *qtImage; + struct QtCanvas : public QWidget { + pCanvas &self; + void leaveEvent(QEvent*); + void mouseMoveEvent(QMouseEvent*); + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void paintEvent(QPaintEvent*); + QtCanvas(pCanvas &self); + } *qtCanvas; + + void setSize(const Size &size); + void update(); + + pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: +}; + +struct pCheckBox : public QObject, public pWidget { + Q_OBJECT + +public: + CheckBox &checkBox; + QCheckBox *qtCheckBox; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckBox(CheckBox &checkBox) : pWidget(checkBox), checkBox(checkBox) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onToggle(); +}; + +struct pComboBox : public QObject, public pWidget { + Q_OBJECT + +public: + ComboBox &comboBox; + QComboBox *qtComboBox; + + void append(const string &text); + void modify(unsigned row, const string &text); + void remove(unsigned row); + Geometry minimumGeometry(); + void reset(); + unsigned selection(); + void setSelection(unsigned row); + + pComboBox(ComboBox &comboBox) : pWidget(comboBox), comboBox(comboBox) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pHexEdit : public QObject, public pWidget { + Q_OBJECT + +public: + HexEdit &hexEdit; + struct QtHexEdit : public QTextEdit { + pHexEdit &self; + void keyPressEvent(QKeyEvent*); + void keyPressEventAcknowledge(QKeyEvent*); + QtHexEdit(pHexEdit &self) : self(self) {} + } *qtHexEdit; + QHBoxLayout *qtLayout; + QScrollBar *qtScroll; + + void setColumns(unsigned columns); + void setLength(unsigned length); + void setOffset(unsigned offset); + void setRows(unsigned rows); + void update(); + + pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} + void constructor(); + void destructor(); + void orphan(); + void keyPressEvent(QKeyEvent*); + +public slots: + void onScroll(); +}; + +struct pHorizontalScrollBar : public QObject, public pWidget { + Q_OBJECT + +public: + HorizontalScrollBar &horizontalScrollBar; + QScrollBar *qtScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pHorizontalSlider : public QObject, public pWidget { + Q_OBJECT + +public: + HorizontalSlider &horizontalSlider; + QSlider *qtSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalSlider(HorizontalSlider &horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pLabel : public pWidget { + Label &label; + QLabel *qtLabel; + + Geometry minimumGeometry(); + void setText(const string &text); + + pLabel(Label &label) : pWidget(label), label(label) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pLineEdit : public QObject, public pWidget { + Q_OBJECT + +public: + LineEdit &lineEdit; + QLineEdit *qtLineEdit; + + Geometry minimumGeometry(); + void setEditable(bool editable); + void setText(const string &text); + string text(); + + pLineEdit(LineEdit &lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onActivate(); + void onChange(); +}; + +struct pListView : public QObject, public pWidget { + Q_OBJECT + +public: + ListView &listView; + QTreeWidget *qtListView; + + void append(const lstring &text); + void autoSizeColumns(); + bool checked(unsigned row); + void modify(unsigned row, const lstring &text); + void remove(unsigned row); + void reset(); + bool selected(); + unsigned selection(); + void setCheckable(bool checkable); + void setChecked(unsigned row, bool checked); + void setHeaderText(const lstring &text); + void setHeaderVisible(bool visible); + void setImage(unsigned row, unsigned column, const nall::image &image); + void setSelected(bool selected); + void setSelection(unsigned row); + + pListView(ListView &listView) : pWidget(listView), listView(listView) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onActivate(); + void onChange(QTreeWidgetItem *item); + void onToggle(QTreeWidgetItem *item); +}; + +struct pProgressBar : public pWidget { + ProgressBar &progressBar; + QProgressBar *qtProgressBar; + + Geometry minimumGeometry(); + void setPosition(unsigned position); + + pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pRadioBox : public QObject, public pWidget { + Q_OBJECT + +public: + RadioBox &radioBox; + QRadioButton *qtRadioBox; + QButtonGroup *qtGroup; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(); + void setGroup(const set &group); + void setText(const string &text); + + pRadioBox(RadioBox &radioBox) : pWidget(radioBox), radioBox(radioBox) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onActivate(); +}; + +struct pTextEdit : public QObject, public pWidget { + Q_OBJECT + +public: + TextEdit &textEdit; + QTextEdit *qtTextEdit; + + void setCursorPosition(unsigned position); + void setEditable(bool editable); + void setText(const string &text); + void setWordWrap(bool wordWrap); + string text(); + + pTextEdit(TextEdit &textEdit) : pWidget(textEdit), textEdit(textEdit) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pVerticalScrollBar : public QObject, public pWidget { + Q_OBJECT + +public: + VerticalScrollBar &verticalScrollBar; + QScrollBar *qtScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pVerticalSlider : public QObject, public pWidget { + Q_OBJECT + +public: + VerticalSlider &verticalSlider; + QSlider *qtSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalSlider(VerticalSlider &verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pViewport : public pWidget { + Viewport &viewport; + struct QtViewport : public QWidget { + pViewport &self; + void leaveEvent(QEvent*); + void mouseMoveEvent(QMouseEvent*); + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + QtViewport(pViewport &self); + } *qtViewport; + + uintptr_t handle(); + + pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} + void constructor(); + void destructor(); + void orphan(); +}; diff --git a/kaijuu/phoenix/qt/settings.cpp b/kaijuu/phoenix/qt/settings.cpp new file mode 100644 index 00000000..90d3a76e --- /dev/null +++ b/kaijuu/phoenix/qt/settings.cpp @@ -0,0 +1,24 @@ +static Settings *settings = nullptr; + +void Settings::load() { + string path = { userpath(), ".config/phoenix/qt.cfg" }; + configuration::load(path); +} + +void Settings::save() { + string path = { userpath(), ".config/" }; + mkdir(path, 0755); + path.append("phoenix/"); + mkdir(path, 0755); + path.append("qt.cfg"); + configuration::save(path); +} + +Settings::Settings() { + append(frameGeometryX = 4, "frameGeometryX"); + append(frameGeometryY = 24, "frameGeometryY"); + append(frameGeometryWidth = 8, "frameGeometryWidth"); + append(frameGeometryHeight = 28, "frameGeometryHeight"); + append(menuGeometryHeight = 20, "menuGeometryHeight"); + append(statusGeometryHeight = 20, "statusGeometryHeight"); +} diff --git a/kaijuu/phoenix/qt/timer.cpp b/kaijuu/phoenix/qt/timer.cpp new file mode 100644 index 00000000..61f00ba8 --- /dev/null +++ b/kaijuu/phoenix/qt/timer.cpp @@ -0,0 +1,25 @@ +void pTimer::setEnabled(bool enabled) { + if(enabled) { + qtTimer->start(); + } else { + qtTimer->stop(); + } +} + +void pTimer::setInterval(unsigned milliseconds) { + qtTimer->setInterval(milliseconds); +} + +void pTimer::constructor() { + qtTimer = new QTimer; + qtTimer->setInterval(0); + connect(qtTimer, SIGNAL(timeout()), SLOT(onTimeout())); +} + +void pTimer::destructor() { + delete qtTimer; +} + +void pTimer::onTimeout() { + if(timer.onTimeout) timer.onTimeout(); +} diff --git a/kaijuu/phoenix/qt/utility.cpp b/kaijuu/phoenix/qt/utility.cpp new file mode 100644 index 00000000..400df0a2 --- /dev/null +++ b/kaijuu/phoenix/qt/utility.cpp @@ -0,0 +1,190 @@ +static QIcon CreateIcon(const nall::image &image, bool scale = false) { + nall::image qtBuffer = image; + qtBuffer.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + if(scale) qtBuffer.scale(16, 16, Interpolation::Linear); + QImage qtImage(qtBuffer.data, qtBuffer.width, qtBuffer.height, QImage::Format_ARGB32); + return QIcon(QPixmap::fromImage(qtImage)); +} + +static Keyboard::Keycode Keysym(int keysym) { + switch(keysym) { + case XK_Escape: return Keyboard::Keycode::Escape; + case XK_F1: return Keyboard::Keycode::F1; + case XK_F2: return Keyboard::Keycode::F2; + case XK_F3: return Keyboard::Keycode::F3; + case XK_F4: return Keyboard::Keycode::F4; + case XK_F5: return Keyboard::Keycode::F5; + case XK_F6: return Keyboard::Keycode::F6; + case XK_F7: return Keyboard::Keycode::F7; + case XK_F8: return Keyboard::Keycode::F8; + case XK_F9: return Keyboard::Keycode::F9; + case XK_F10: return Keyboard::Keycode::F10; + case XK_F11: return Keyboard::Keycode::F11; + case XK_F12: return Keyboard::Keycode::F12; + + case XK_Print: return Keyboard::Keycode::PrintScreen; + //Keyboard::Keycode::SysRq + case XK_Scroll_Lock: return Keyboard::Keycode::ScrollLock; + case XK_Pause: return Keyboard::Keycode::Pause; + //Keyboard::Keycode::Break + + case XK_Insert: return Keyboard::Keycode::Insert; + case XK_Delete: return Keyboard::Keycode::Delete; + case XK_Home: return Keyboard::Keycode::Home; + case XK_End: return Keyboard::Keycode::End; + case XK_Prior: return Keyboard::Keycode::PageUp; + case XK_Next: return Keyboard::Keycode::PageDown; + + case XK_Up: return Keyboard::Keycode::Up; + case XK_Down: return Keyboard::Keycode::Down; + case XK_Left: return Keyboard::Keycode::Left; + case XK_Right: return Keyboard::Keycode::Right; + + case XK_grave: return Keyboard::Keycode::Grave; + case XK_1: return Keyboard::Keycode::Number1; + case XK_2: return Keyboard::Keycode::Number2; + case XK_3: return Keyboard::Keycode::Number3; + case XK_4: return Keyboard::Keycode::Number4; + case XK_5: return Keyboard::Keycode::Number5; + case XK_6: return Keyboard::Keycode::Number6; + case XK_7: return Keyboard::Keycode::Number7; + case XK_8: return Keyboard::Keycode::Number8; + case XK_9: return Keyboard::Keycode::Number9; + case XK_0: return Keyboard::Keycode::Number0; + case XK_minus: return Keyboard::Keycode::Minus; + case XK_equal: return Keyboard::Keycode::Equal; + case XK_BackSpace: return Keyboard::Keycode::Backspace; + + case XK_asciitilde: return Keyboard::Keycode::Tilde; + case XK_exclam: return Keyboard::Keycode::Exclamation; + case XK_at: return Keyboard::Keycode::At; + case XK_numbersign: return Keyboard::Keycode::Pound; + case XK_dollar: return Keyboard::Keycode::Dollar; + case XK_percent: return Keyboard::Keycode::Percent; + case XK_asciicircum: return Keyboard::Keycode::Power; + case XK_ampersand: return Keyboard::Keycode::Ampersand; + case XK_asterisk: return Keyboard::Keycode::Asterisk; + case XK_parenleft: return Keyboard::Keycode::ParenthesisLeft; + case XK_parenright: return Keyboard::Keycode::ParenthesisRight; + case XK_underscore: return Keyboard::Keycode::Underscore; + case XK_plus: return Keyboard::Keycode::Plus; + + case XK_bracketleft: return Keyboard::Keycode::BracketLeft; + case XK_bracketright: return Keyboard::Keycode::BracketRight; + case XK_backslash: return Keyboard::Keycode::Backslash; + case XK_semicolon: return Keyboard::Keycode::Semicolon; + case XK_apostrophe: return Keyboard::Keycode::Apostrophe; + case XK_comma: return Keyboard::Keycode::Comma; + case XK_period: return Keyboard::Keycode::Period; + case XK_slash: return Keyboard::Keycode::Slash; + + case XK_braceleft: return Keyboard::Keycode::BraceLeft; + case XK_braceright: return Keyboard::Keycode::BraceRight; + case XK_bar: return Keyboard::Keycode::Pipe; + case XK_colon: return Keyboard::Keycode::Colon; + case XK_quotedbl: return Keyboard::Keycode::Quote; + case XK_less: return Keyboard::Keycode::CaretLeft; + case XK_greater: return Keyboard::Keycode::CaretRight; + case XK_question: return Keyboard::Keycode::Question; + + case XK_Tab: return Keyboard::Keycode::Tab; + case XK_Caps_Lock: return Keyboard::Keycode::CapsLock; + case XK_Return: return Keyboard::Keycode::Return; + case XK_Shift_L: return Keyboard::Keycode::ShiftLeft; + case XK_Shift_R: return Keyboard::Keycode::ShiftRight; + case XK_Control_L: return Keyboard::Keycode::ControlLeft; + case XK_Control_R: return Keyboard::Keycode::ControlRight; + case XK_Super_L: return Keyboard::Keycode::SuperLeft; + case XK_Super_R: return Keyboard::Keycode::SuperRight; + case XK_Alt_L: return Keyboard::Keycode::AltLeft; + case XK_Alt_R: return Keyboard::Keycode::AltRight; + case XK_space: return Keyboard::Keycode::Space; + case XK_Menu: return Keyboard::Keycode::Menu; + + case XK_A: return Keyboard::Keycode::A; + case XK_B: return Keyboard::Keycode::B; + case XK_C: return Keyboard::Keycode::C; + case XK_D: return Keyboard::Keycode::D; + case XK_E: return Keyboard::Keycode::E; + case XK_F: return Keyboard::Keycode::F; + case XK_G: return Keyboard::Keycode::G; + case XK_H: return Keyboard::Keycode::H; + case XK_I: return Keyboard::Keycode::I; + case XK_J: return Keyboard::Keycode::J; + case XK_K: return Keyboard::Keycode::K; + case XK_L: return Keyboard::Keycode::L; + case XK_M: return Keyboard::Keycode::M; + case XK_N: return Keyboard::Keycode::N; + case XK_O: return Keyboard::Keycode::O; + case XK_P: return Keyboard::Keycode::P; + case XK_Q: return Keyboard::Keycode::Q; + case XK_R: return Keyboard::Keycode::R; + case XK_S: return Keyboard::Keycode::S; + case XK_T: return Keyboard::Keycode::T; + case XK_U: return Keyboard::Keycode::U; + case XK_V: return Keyboard::Keycode::V; + case XK_W: return Keyboard::Keycode::W; + case XK_X: return Keyboard::Keycode::X; + case XK_Y: return Keyboard::Keycode::Y; + case XK_Z: return Keyboard::Keycode::Z; + + case XK_a: return Keyboard::Keycode::a; + case XK_b: return Keyboard::Keycode::b; + case XK_c: return Keyboard::Keycode::c; + case XK_d: return Keyboard::Keycode::d; + case XK_e: return Keyboard::Keycode::e; + case XK_f: return Keyboard::Keycode::f; + case XK_g: return Keyboard::Keycode::g; + case XK_h: return Keyboard::Keycode::h; + case XK_i: return Keyboard::Keycode::i; + case XK_j: return Keyboard::Keycode::j; + case XK_k: return Keyboard::Keycode::k; + case XK_l: return Keyboard::Keycode::l; + case XK_m: return Keyboard::Keycode::m; + case XK_n: return Keyboard::Keycode::n; + case XK_o: return Keyboard::Keycode::o; + case XK_p: return Keyboard::Keycode::p; + case XK_q: return Keyboard::Keycode::q; + case XK_r: return Keyboard::Keycode::r; + case XK_s: return Keyboard::Keycode::s; + case XK_t: return Keyboard::Keycode::t; + case XK_u: return Keyboard::Keycode::u; + case XK_v: return Keyboard::Keycode::v; + case XK_w: return Keyboard::Keycode::w; + case XK_x: return Keyboard::Keycode::x; + case XK_y: return Keyboard::Keycode::y; + case XK_z: return Keyboard::Keycode::z; + + case XK_Num_Lock: return Keyboard::Keycode::NumLock; + case XK_KP_Divide: return Keyboard::Keycode::Divide; + case XK_KP_Multiply: return Keyboard::Keycode::Multiply; + case XK_KP_Subtract: return Keyboard::Keycode::Subtract; + case XK_KP_Add: return Keyboard::Keycode::Add; + case XK_KP_Enter: return Keyboard::Keycode::Enter; + case XK_KP_Decimal: return Keyboard::Keycode::Point; + + case XK_KP_1: return Keyboard::Keycode::Keypad1; + case XK_KP_2: return Keyboard::Keycode::Keypad2; + case XK_KP_3: return Keyboard::Keycode::Keypad3; + case XK_KP_4: return Keyboard::Keycode::Keypad4; + case XK_KP_5: return Keyboard::Keycode::Keypad5; + case XK_KP_6: return Keyboard::Keycode::Keypad6; + case XK_KP_7: return Keyboard::Keycode::Keypad7; + case XK_KP_8: return Keyboard::Keycode::Keypad8; + case XK_KP_9: return Keyboard::Keycode::Keypad9; + case XK_KP_0: return Keyboard::Keycode::Keypad0; + + case XK_KP_Home: return Keyboard::Keycode::KeypadHome; + case XK_KP_End: return Keyboard::Keycode::KeypadEnd; + case XK_KP_Page_Up: return Keyboard::Keycode::KeypadPageUp; + case XK_KP_Page_Down: return Keyboard::Keycode::KeypadPageDown; + case XK_KP_Up: return Keyboard::Keycode::KeypadUp; + case XK_KP_Down: return Keyboard::Keycode::KeypadDown; + case XK_KP_Left: return Keyboard::Keycode::KeypadLeft; + case XK_KP_Right: return Keyboard::Keycode::KeypadRight; + case XK_KP_Begin: return Keyboard::Keycode::KeypadCenter; + case XK_KP_Insert: return Keyboard::Keycode::KeypadInsert; + case XK_KP_Delete: return Keyboard::Keycode::KeypadDelete; + } + return Keyboard::Keycode::None; +} diff --git a/kaijuu/phoenix/qt/widget/button.cpp b/kaijuu/phoenix/qt/widget/button.cpp new file mode 100644 index 00000000..0e1522b3 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/button.cpp @@ -0,0 +1,52 @@ +Geometry pButton::minimumGeometry() { + Geometry geometry = pFont::geometry(qtWidget->font(), button.state.text); + + if(button.state.orientation == Orientation::Horizontal) { + geometry.width += button.state.image.width; + geometry.height = max(button.state.image.height, geometry.height); + } + + if(button.state.orientation == Orientation::Vertical) { + geometry.width = max(button.state.image.width, geometry.width); + geometry.height += button.state.image.height; + } + + return { 0, 0, geometry.width + 20, geometry.height + 12 }; +} + +void pButton::setImage(const image &image, Orientation orientation) { + qtButton->setIconSize(QSize(image.width, image.height)); + qtButton->setIcon(CreateIcon(image)); + qtButton->setStyleSheet("text-align: top;"); + switch(orientation) { + case Orientation::Horizontal: qtButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); break; + case Orientation::Vertical: qtButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); break; + } +} + +void pButton::setText(const string &text) { + qtButton->setText(QString::fromUtf8(text)); +} + +void pButton::constructor() { + qtWidget = qtButton = new QToolButton; + qtButton->setToolButtonStyle(Qt::ToolButtonTextOnly); + connect(qtButton, SIGNAL(released()), SLOT(onActivate())); + + pWidget::synchronizeState(); + setText(button.state.text); +} + +void pButton::destructor() { + delete qtButton; + qtWidget = qtButton = 0; +} + +void pButton::orphan() { + destructor(); + constructor(); +} + +void pButton::onActivate() { + if(button.onActivate) button.onActivate(); +} diff --git a/kaijuu/phoenix/qt/widget/canvas.cpp b/kaijuu/phoenix/qt/widget/canvas.cpp new file mode 100644 index 00000000..245c1e9f --- /dev/null +++ b/kaijuu/phoenix/qt/widget/canvas.cpp @@ -0,0 +1,73 @@ +void pCanvas::setSize(const Size &size) { + delete qtImage; + qtImage = new QImage(size.width, size.height, QImage::Format_ARGB32); +} + +void pCanvas::update() { + uint32_t *dp = (uint32_t*)qtImage->bits(), *sp = (uint32_t*)canvas.state.data; + for(unsigned n = 0; n < canvas.state.width * canvas.state.height; n++) *dp++ = 0xff000000 | *sp++; + qtCanvas->update(); +} + +void pCanvas::constructor() { + qtWidget = qtCanvas = new QtCanvas(*this); + qtCanvas->setMouseTracking(true); + qtImage = new QImage(canvas.state.width, canvas.state.height, QImage::Format_ARGB32); + memcpy(qtImage->bits(), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); + + pWidget::synchronizeState(); + update(); +} + +void pCanvas::destructor() { + delete qtCanvas; + delete qtImage; + qtWidget = qtCanvas = 0; + qtImage = 0; +} + +void pCanvas::orphan() { + destructor(); + constructor(); +} + +void pCanvas::QtCanvas::leaveEvent(QEvent *event) { + if(self.canvas.onMouseLeave) self.canvas.onMouseLeave(); +} + +void pCanvas::QtCanvas::mouseMoveEvent(QMouseEvent *event) { + if(self.canvas.onMouseMove) self.canvas.onMouseMove({ event->pos().x(), event->pos().y() }); +} + +void pCanvas::QtCanvas::mousePressEvent(QMouseEvent *event) { + if(self.canvas.onMousePress == false) return; + switch(event->button()) { + case Qt::LeftButton: self.canvas.onMousePress(Mouse::Button::Left); break; + case Qt::MidButton: self.canvas.onMousePress(Mouse::Button::Middle); break; + case Qt::RightButton: self.canvas.onMousePress(Mouse::Button::Right); break; + } +} + +void pCanvas::QtCanvas::mouseReleaseEvent(QMouseEvent *event) { + if(self.canvas.onMouseRelease == false) return; + switch(event->button()) { + case Qt::LeftButton: self.canvas.onMouseRelease(Mouse::Button::Left); break; + case Qt::MidButton: self.canvas.onMouseRelease(Mouse::Button::Middle); break; + case Qt::RightButton: self.canvas.onMouseRelease(Mouse::Button::Right); break; + } +} + +void pCanvas::QtCanvas::paintEvent(QPaintEvent *event) { + QPainter painter(self.qtCanvas); + painter.drawImage(0, 0, *self.qtImage); + +//this will scale the source image to fit the target widget size (nearest-neighbor): +//painter.drawImage( +// QRect(0, 0, geometry().width(), geometry().height()), +// *self.qtImage, +// QRect(0, 0, self.canvas.state.width, self.canvas.state.height) +//); +} + +pCanvas::QtCanvas::QtCanvas(pCanvas &self) : self(self) { +} diff --git a/kaijuu/phoenix/qt/widget/check-box.cpp b/kaijuu/phoenix/qt/widget/check-box.cpp new file mode 100644 index 00000000..c45bb326 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/check-box.cpp @@ -0,0 +1,42 @@ +bool pCheckBox::checked() { + return qtCheckBox->isChecked(); +} + +Geometry pCheckBox::minimumGeometry() { + Geometry geometry = pFont::geometry(qtWidget->font(), checkBox.state.text); + return { 0, 0, geometry.width + 26, geometry.height + 6 }; +} + +void pCheckBox::setChecked(bool checked) { + locked = true; + qtCheckBox->setChecked(checked); + locked = false; +} + +void pCheckBox::setText(const string &text) { + qtCheckBox->setText(QString::fromUtf8(text)); +} + +void pCheckBox::constructor() { + qtWidget = qtCheckBox = new QCheckBox; + connect(qtCheckBox, SIGNAL(stateChanged(int)), SLOT(onToggle())); + + pWidget::synchronizeState(); + setChecked(checkBox.state.checked); + setText(checkBox.state.text); +} + +void pCheckBox::destructor() { + delete qtCheckBox; + qtWidget = qtCheckBox = 0; +} + +void pCheckBox::orphan() { + destructor(); + constructor(); +} + +void pCheckBox::onToggle() { + checkBox.state.checked = checked(); + if(locked == false && checkBox.onToggle) checkBox.onToggle(); +} diff --git a/kaijuu/phoenix/qt/widget/combo-box.cpp b/kaijuu/phoenix/qt/widget/combo-box.cpp new file mode 100644 index 00000000..1dfa609d --- /dev/null +++ b/kaijuu/phoenix/qt/widget/combo-box.cpp @@ -0,0 +1,68 @@ +void pComboBox::append(const string &text) { + locked = true; + qtComboBox->addItem(QString::fromUtf8(text)); + locked = false; +} + +Geometry pComboBox::minimumGeometry() { + unsigned maximumWidth = 0; + for(auto &text : comboBox.state.text) maximumWidth = max(maximumWidth, pFont::geometry(qtWidget->font(), text).width); + Geometry geometry = pFont::geometry(qtWidget->font(), " "); + return { 0, 0, maximumWidth + 32, geometry.height + 12 }; +} + +void pComboBox::modify(unsigned row, const string &text) { + qtComboBox->setItemText(row, text); +} + +void pComboBox::remove(unsigned row) { + locked = true; + unsigned position = selection(); + qtComboBox->removeItem(row); + if(position == row) qtComboBox->setCurrentIndex(0); + locked = false; +} + +void pComboBox::reset() { + locked = true; + while(qtComboBox->count()) qtComboBox->removeItem(0); + locked = false; +} + +unsigned pComboBox::selection() { + signed index = qtComboBox->currentIndex(); + return index >= 0 ? index : 0; +} + +void pComboBox::setSelection(unsigned row) { + locked = true; + qtComboBox->setCurrentIndex(row); + locked = false; +} + +void pComboBox::constructor() { + qtWidget = qtComboBox = new QComboBox; + connect(qtComboBox, SIGNAL(currentIndexChanged(int)), SLOT(onChange())); + + pWidget::synchronizeState(); + unsigned selection = comboBox.state.selection; + locked = true; + for(auto &text : comboBox.state.text) append(text); + locked = false; + setSelection(selection); +} + +void pComboBox::destructor() { + delete qtComboBox; + qtWidget = qtComboBox = 0; +} + +void pComboBox::orphan() { + destructor(); + constructor(); +} + +void pComboBox::onChange() { + comboBox.state.selection = selection(); + if(locked == false && comboBox.onChange) comboBox.onChange(); +} diff --git a/kaijuu/phoenix/qt/widget/hex-edit.cpp b/kaijuu/phoenix/qt/widget/hex-edit.cpp new file mode 100644 index 00000000..fdeebe4a --- /dev/null +++ b/kaijuu/phoenix/qt/widget/hex-edit.cpp @@ -0,0 +1,191 @@ +void pHexEdit::setColumns(unsigned columns) { + update(); +} + +void pHexEdit::setLength(unsigned length) { + //add one if last row is not equal to column length (eg only part of the row is present) + bool indivisible = hexEdit.state.columns == 0 || (hexEdit.state.length % hexEdit.state.columns) != 0; + qtScroll->setRange(0, hexEdit.state.length / hexEdit.state.columns + indivisible - hexEdit.state.rows); + update(); +} + +void pHexEdit::setOffset(unsigned offset) { + locked = true; + qtScroll->setSliderPosition(hexEdit.state.offset / hexEdit.state.columns); + locked = false; + update(); +} + +void pHexEdit::setRows(unsigned rows) { + qtScroll->setPageStep(hexEdit.state.rows); + update(); +} + +void pHexEdit::update() { + if(!hexEdit.onRead) { + qtHexEdit->setPlainText(""); + return; + } + + unsigned cursorPosition = qtHexEdit->textCursor().position(); + + string output; + unsigned offset = hexEdit.state.offset; + for(unsigned row = 0; row < hexEdit.state.rows; row++) { + output.append(hex<8>(offset)); + output.append(" "); + + string hexdata; + string ansidata = " "; + + for(unsigned column = 0; column < hexEdit.state.columns; column++) { + if(offset < hexEdit.state.length) { + uint8_t data = hexEdit.onRead(offset++); + hexdata.append(hex<2>(data)); + hexdata.append(" "); + char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 }; + ansidata.append(buffer); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(offset >= hexEdit.state.length) break; + if(row != hexEdit.state.rows - 1) output.append("\n"); + } + + qtHexEdit->setPlainText(QString::fromUtf8(output)); + QTextCursor cursor = qtHexEdit->textCursor(); + cursor.setPosition(cursorPosition); + qtHexEdit->setTextCursor(cursor); +} + +void pHexEdit::constructor() { + qtWidget = qtHexEdit = new QtHexEdit(*this); + + qtHexEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + qtHexEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + qtLayout = new QHBoxLayout; + qtLayout->setAlignment(Qt::AlignRight); + qtLayout->setMargin(0); + qtLayout->setSpacing(0); + qtHexEdit->setLayout(qtLayout); + + qtScroll = new QScrollBar(Qt::Vertical); + qtScroll->setSingleStep(1); + qtLayout->addWidget(qtScroll); + + connect(qtScroll, SIGNAL(actionTriggered(int)), SLOT(onScroll())); + + pWidget::synchronizeState(); + setColumns(hexEdit.state.columns); + setRows(hexEdit.state.rows); + setLength(hexEdit.state.length); + setOffset(hexEdit.state.offset); + update(); +} + +void pHexEdit::destructor() { + delete qtScroll; + delete qtLayout; + delete qtHexEdit; + qtWidget = qtHexEdit = 0; + qtLayout = 0; + qtScroll = 0; +} + +void pHexEdit::orphan() { + destructor(); + constructor(); +} + +void pHexEdit::keyPressEvent(QKeyEvent *event) { + if(!hexEdit.onRead) return; + + QTextCursor cursor = qtHexEdit->textCursor(); + unsigned lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 1; + unsigned cursorY = cursor.position() / lineWidth; + unsigned cursorX = cursor.position() % lineWidth; + + unsigned nibble; + switch(event->key()) { + case Qt::Key_0: nibble = 0; break; + case Qt::Key_1: nibble = 1; break; + case Qt::Key_2: nibble = 2; break; + case Qt::Key_3: nibble = 3; break; + case Qt::Key_4: nibble = 4; break; + case Qt::Key_5: nibble = 5; break; + case Qt::Key_6: nibble = 6; break; + case Qt::Key_7: nibble = 7; break; + case Qt::Key_8: nibble = 8; break; + case Qt::Key_9: nibble = 9; break; + case Qt::Key_A: nibble = 10; break; + case Qt::Key_B: nibble = 11; break; + case Qt::Key_C: nibble = 12; break; + case Qt::Key_D: nibble = 13; break; + case Qt::Key_E: nibble = 14; break; + case Qt::Key_F: nibble = 15; break; + default: { + //allow navigation keys to move cursor, but block text input + qtHexEdit->setTextInteractionFlags(Qt::TextInteractionFlags( + Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse + )); + qtHexEdit->keyPressEventAcknowledge(event); + qtHexEdit->setTextInteractionFlags(Qt::TextEditorInteraction); + return; + } + } + + if(cursorX >= 10) { + //not on an offset + cursorX -= 10; + if((cursorX % 3) != 2) { + //not on a space + bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low + cursorX /= 3; + if(cursorX < hexEdit.state.columns) { + //not in ANSI region + unsigned offset = hexEdit.state.offset + (cursorY * hexEdit.state.columns + cursorX); + + if(offset >= hexEdit.state.length) return; //do not edit past end of file + uint8_t data = hexEdit.onRead(offset); + + //write modified value + if(cursorNibble == 1) { + data = (data & 0xf0) | (nibble << 0); + } else { + data = (data & 0x0f) | (nibble << 4); + } + if(hexEdit.onWrite) hexEdit.onWrite(offset, data); + + //auto-advance cursor to next nibble/byte + unsigned step = 1; + if(cursorNibble && cursorX != hexEdit.state.columns - 1) step = 2; + cursor.setPosition(cursor.position() + step); + qtHexEdit->setTextCursor(cursor); + + //refresh output to reflect modified data + update(); + } + } + } +} + +void pHexEdit::onScroll() { + if(locked) return; + unsigned offset = qtScroll->sliderPosition(); + hexEdit.state.offset = offset * hexEdit.state.columns; + update(); +} + +void pHexEdit::QtHexEdit::keyPressEvent(QKeyEvent *event) { + self.keyPressEvent(event); +} + +void pHexEdit::QtHexEdit::keyPressEventAcknowledge(QKeyEvent *event) { + QTextEdit::keyPressEvent(event); +} diff --git a/kaijuu/phoenix/qt/widget/horizontal-scroll-bar.cpp b/kaijuu/phoenix/qt/widget/horizontal-scroll-bar.cpp new file mode 100644 index 00000000..6127c301 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,43 @@ +Geometry pHorizontalScrollBar::minimumGeometry() { + return { 0, 0, 0, 15 }; +} + +unsigned pHorizontalScrollBar::position() { + return qtScrollBar->value(); +} + +void pHorizontalScrollBar::setLength(unsigned length) { + length += length == 0; + qtScrollBar->setRange(0, length - 1); + qtScrollBar->setPageStep(length >> 3); +} + +void pHorizontalScrollBar::setPosition(unsigned position) { + qtScrollBar->setValue(position); +} + +void pHorizontalScrollBar::constructor() { + qtWidget = qtScrollBar = new QScrollBar(Qt::Horizontal); + qtScrollBar->setRange(0, 100); + qtScrollBar->setPageStep(101 >> 3); + connect(qtScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::synchronizeState(); + setLength(horizontalScrollBar.state.length); + setPosition(horizontalScrollBar.state.position); +} + +void pHorizontalScrollBar::destructor() { + delete qtScrollBar; + qtWidget = qtScrollBar = 0; +} + +void pHorizontalScrollBar::orphan() { + destructor(); + constructor(); +} + +void pHorizontalScrollBar::onChange() { + horizontalScrollBar.state.position = position(); + if(horizontalScrollBar.onChange) horizontalScrollBar.onChange(); +} diff --git a/kaijuu/phoenix/qt/widget/horizontal-slider.cpp b/kaijuu/phoenix/qt/widget/horizontal-slider.cpp new file mode 100644 index 00000000..5401aae1 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/horizontal-slider.cpp @@ -0,0 +1,43 @@ +Geometry pHorizontalSlider::minimumGeometry() { + return { 0, 0, 0, 20 }; +} + +unsigned pHorizontalSlider::position() { + return qtSlider->value(); +} + +void pHorizontalSlider::setLength(unsigned length) { + length += length == 0; + qtSlider->setRange(0, length - 1); + qtSlider->setPageStep(length >> 3); +} + +void pHorizontalSlider::setPosition(unsigned position) { + qtSlider->setValue(position); +} + +void pHorizontalSlider::constructor() { + qtWidget = qtSlider = new QSlider(Qt::Horizontal); + qtSlider->setRange(0, 100); + qtSlider->setPageStep(101 >> 3); + connect(qtSlider, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::synchronizeState(); + setLength(horizontalSlider.state.length); + setPosition(horizontalSlider.state.position); +} + +void pHorizontalSlider::destructor() { + delete qtSlider; + qtWidget = qtSlider = 0; +} + +void pHorizontalSlider::orphan() { + destructor(); + constructor(); +} + +void pHorizontalSlider::onChange() { + horizontalSlider.state.position = position(); + if(horizontalSlider.onChange) horizontalSlider.onChange(); +} diff --git a/kaijuu/phoenix/qt/widget/label.cpp b/kaijuu/phoenix/qt/widget/label.cpp new file mode 100644 index 00000000..8dd86eb6 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/label.cpp @@ -0,0 +1,25 @@ +Geometry pLabel::minimumGeometry() { + Geometry geometry = pFont::geometry(qtWidget->font(), label.state.text); + return { 0, 0, geometry.width, geometry.height }; +} + +void pLabel::setText(const string &text) { + qtLabel->setText(QString::fromUtf8(text)); +} + +void pLabel::constructor() { + qtWidget = qtLabel = new QLabel; + + pWidget::synchronizeState(); + setText(label.state.text); +} + +void pLabel::destructor() { + delete qtLabel; + qtWidget = qtLabel = 0; +} + +void pLabel::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/qt/widget/line-edit.cpp b/kaijuu/phoenix/qt/widget/line-edit.cpp new file mode 100644 index 00000000..a13f3b81 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/line-edit.cpp @@ -0,0 +1,45 @@ +Geometry pLineEdit::minimumGeometry() { + Geometry geometry = pFont::geometry(qtWidget->font(), lineEdit.state.text); + return { 0, 0, geometry.width + 12, geometry.height + 12 }; +} + +void pLineEdit::setEditable(bool editable) { + qtLineEdit->setReadOnly(!editable); +} + +void pLineEdit::setText(const string &text) { + qtLineEdit->setText(QString::fromUtf8(text)); +} + +string pLineEdit::text() { + return qtLineEdit->text().toUtf8().constData(); +} + +void pLineEdit::constructor() { + qtWidget = qtLineEdit = new QLineEdit; + connect(qtLineEdit, SIGNAL(returnPressed()), SLOT(onActivate())); + connect(qtLineEdit, SIGNAL(textEdited(const QString&)), SLOT(onChange())); + + pWidget::synchronizeState(); + setEditable(lineEdit.state.editable); + setText(lineEdit.state.text); +} + +void pLineEdit::destructor() { + delete qtLineEdit; + qtWidget = qtLineEdit = 0; +} + +void pLineEdit::orphan() { + destructor(); + constructor(); +} + +void pLineEdit::onActivate() { + if(lineEdit.onActivate) lineEdit.onActivate(); +} + +void pLineEdit::onChange() { + lineEdit.state.text = text(); + if(lineEdit.onChange) lineEdit.onChange(); +} diff --git a/kaijuu/phoenix/qt/widget/list-view.cpp b/kaijuu/phoenix/qt/widget/list-view.cpp new file mode 100644 index 00000000..a81c092d --- /dev/null +++ b/kaijuu/phoenix/qt/widget/list-view.cpp @@ -0,0 +1,164 @@ +void pListView::append(const lstring &text) { + locked = true; + auto items = qtListView->findItems("", Qt::MatchContains); + QTreeWidgetItem *item = new QTreeWidgetItem(qtListView); + + item->setData(0, Qt::UserRole, (unsigned)items.size()); + if(listView.state.checkable) item->setCheckState(0, Qt::Unchecked); + for(unsigned n = 0; n < text.size(); n++) { + item->setText(n, QString::fromUtf8(text[n])); + } + locked = false; +} + +void pListView::autoSizeColumns() { + for(unsigned n = 0; n < listView.state.headerText.size(); n++) qtListView->resizeColumnToContents(n); +} + +bool pListView::checked(unsigned row) { + QTreeWidgetItem *item = qtListView->topLevelItem(row); + return item ? item->checkState(0) == Qt::Checked : false; +} + +void pListView::modify(unsigned row, const lstring &text) { + locked = true; + QTreeWidgetItem *item = qtListView->topLevelItem(row); + if(item == nullptr) return; + for(unsigned n = 0; n < text.size(); n++) { + item->setText(n, QString::fromUtf8(text[n])); + } + locked = false; +} + +void pListView::remove(unsigned row) { + locked = true; + QTreeWidgetItem *item = qtListView->topLevelItem(row); + if(item == nullptr) return; + delete item; + locked = false; +} + +void pListView::reset() { + qtListView->clear(); +} + +bool pListView::selected() { + QTreeWidgetItem *item = qtListView->currentItem(); + return (item && item->isSelected() == true); +} + +unsigned pListView::selection() { + QTreeWidgetItem *item = qtListView->currentItem(); + if(item == 0) return 0; + return item->data(0, Qt::UserRole).toUInt(); +} + +void pListView::setCheckable(bool checkable) { + if(checkable) { + auto items = qtListView->findItems("", Qt::MatchContains); + for(unsigned n = 0; n < items.size(); n++) items[n]->setCheckState(0, Qt::Unchecked); + } +} + +void pListView::setChecked(unsigned row, bool checked) { + locked = true; + QTreeWidgetItem *item = qtListView->topLevelItem(row); + if(item) item->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked); + locked = false; +} + +void pListView::setHeaderText(const lstring &text) { + QStringList labels; + for(auto &column : text) labels << QString::fromUtf8(column); + + qtListView->setColumnCount(text.size()); + qtListView->setAlternatingRowColors(text.size() >= 2); + qtListView->setHeaderLabels(labels); + autoSizeColumns(); +} + +void pListView::setHeaderVisible(bool visible) { + qtListView->setHeaderHidden(!visible); + autoSizeColumns(); +} + +void pListView::setImage(unsigned row, unsigned column, const nall::image &image) { + QTreeWidgetItem *item = qtListView->topLevelItem(row); + if(item) { + if(image.empty() == 0) item->setIcon(column, CreateIcon(image)); + if(image.empty() == 1) item->setIcon(column, QIcon()); + } +} + +void pListView::setSelected(bool selected) { + QTreeWidgetItem *item = qtListView->currentItem(); + if(item) item->setSelected(selected); +} + +void pListView::setSelection(unsigned row) { + locked = true; + QTreeWidgetItem *item = qtListView->currentItem(); + if(item) item->setSelected(false); + qtListView->setCurrentItem(0); + auto items = qtListView->findItems("", Qt::MatchContains); + for(unsigned n = 0; n < items.size(); n++) { + if(items[n]->data(0, Qt::UserRole).toUInt() == row) { + qtListView->setCurrentItem(items[n]); + break; + } + } + locked = false; +} + +void pListView::constructor() { + qtWidget = qtListView = new QTreeWidget; + qtListView->setAllColumnsShowFocus(true); + qtListView->setRootIsDecorated(false); + + connect(qtListView, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate())); + connect(qtListView, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), SLOT(onChange(QTreeWidgetItem*))); + connect(qtListView, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onToggle(QTreeWidgetItem*))); + + pWidget::synchronizeState(); + setCheckable(listView.state.checkable); + setHeaderText(listView.state.headerText.size() ? listView.state.headerText : lstring{ " " }); + setHeaderVisible(listView.state.headerVisible); + for(auto &row : listView.state.text) append(row); + if(listView.state.checkable) { + for(unsigned n = 0; n < listView.state.checked.size(); n++) { + setChecked(n, listView.state.checked[n]); + } + } + setSelected(listView.state.selected); + if(listView.state.selected) setSelection(listView.state.selection); + autoSizeColumns(); +} + +void pListView::destructor() { + delete qtListView; + qtWidget = qtListView = 0; +} + +void pListView::orphan() { + destructor(); + constructor(); +} + +void pListView::onActivate() { + if(locked == false && listView.onActivate) listView.onActivate(); +} + +void pListView::onChange(QTreeWidgetItem *item) { + //Qt bug workaround: clicking items with mouse does not mark items as selected + if(item) item->setSelected(true); + listView.state.selected = selected(); + if(listView.state.selected) listView.state.selection = selection(); + if(locked == false && listView.onChange) listView.onChange(); +} + +void pListView::onToggle(QTreeWidgetItem *item) { + unsigned row = item->data(0, Qt::UserRole).toUInt(); + bool checkState = checked(row); + listView.state.checked[row] = checkState; + if(locked == false && listView.onToggle) listView.onToggle(row); +} diff --git a/kaijuu/phoenix/qt/widget/progress-bar.cpp b/kaijuu/phoenix/qt/widget/progress-bar.cpp new file mode 100644 index 00000000..8178bb66 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/progress-bar.cpp @@ -0,0 +1,26 @@ +Geometry pProgressBar::minimumGeometry() { + return { 0, 0, 0, 25 }; +} + +void pProgressBar::setPosition(unsigned position) { + qtProgressBar->setValue(position); +} + +void pProgressBar::constructor() { + qtWidget = qtProgressBar = new QProgressBar; + qtProgressBar->setRange(0, 100); + qtProgressBar->setTextVisible(false); + + pWidget::synchronizeState(); + setPosition(progressBar.state.position); +} + +void pProgressBar::destructor() { + delete qtProgressBar; + qtWidget = qtProgressBar = 0; +} + +void pProgressBar::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/qt/widget/radio-box.cpp b/kaijuu/phoenix/qt/widget/radio-box.cpp new file mode 100644 index 00000000..bf640fd2 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/radio-box.cpp @@ -0,0 +1,64 @@ +bool pRadioBox::checked() { + return qtRadioBox->isChecked(); +} + +Geometry pRadioBox::minimumGeometry() { + Geometry geometry = pFont::geometry(qtWidget->font(), radioBox.state.text); + return { 0, 0, geometry.width + 26, geometry.height + 6 }; +} + +void pRadioBox::setChecked() { + locked = true; + for(auto &item : radioBox.state.group) { + bool checkState = item.p.qtRadioBox == qtRadioBox; + item.state.checked = checkState; + item.p.qtRadioBox->setChecked(checkState); + } + locked = false; +} + +void pRadioBox::setGroup(const set &group) { + locked = true; + if(qtGroup) { + delete qtGroup; + qtGroup = 0; + } + if(group.size() > 0 && qtRadioBox == group[0].p.qtRadioBox) { + qtGroup = new QButtonGroup; + for(auto &item : group) qtGroup->addButton(item.p.qtRadioBox); + setChecked(); + } + locked = false; +} + +void pRadioBox::setText(const string &text) { + qtRadioBox->setText(QString::fromUtf8(text)); +} + +void pRadioBox::constructor() { + qtWidget = qtRadioBox = new QRadioButton; + qtGroup = new QButtonGroup; + qtGroup->addButton(qtRadioBox); + qtRadioBox->setChecked(true); + connect(qtRadioBox, SIGNAL(toggled(bool)), SLOT(onActivate())); + + pWidget::synchronizeState(); + setGroup(radioBox.state.group); + setText(radioBox.state.text); +} + +void pRadioBox::destructor() { + delete qtGroup; + delete qtRadioBox; + qtWidget = qtRadioBox = 0; + qtGroup = 0; +} + +void pRadioBox::orphan() { + destructor(); + constructor(); +} + +void pRadioBox::onActivate() { + if(locked == false && checked() && radioBox.onActivate) radioBox.onActivate(); +} diff --git a/kaijuu/phoenix/qt/widget/text-edit.cpp b/kaijuu/phoenix/qt/widget/text-edit.cpp new file mode 100644 index 00000000..8cdbe573 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/text-edit.cpp @@ -0,0 +1,50 @@ +void pTextEdit::setCursorPosition(unsigned position) { + QTextCursor cursor = qtTextEdit->textCursor(); + unsigned lastCharacter = strlen(qtTextEdit->toPlainText().toUtf8().constData()); + cursor.setPosition(min(position, lastCharacter)); + qtTextEdit->setTextCursor(cursor); +} + +void pTextEdit::setEditable(bool editable) { + qtTextEdit->setReadOnly(!editable); +} + +void pTextEdit::setText(const string &text) { + qtTextEdit->setPlainText(QString::fromUtf8(text)); +} + +void pTextEdit::setWordWrap(bool wordWrap) { + qtTextEdit->setWordWrapMode(wordWrap ? QTextOption::WordWrap : QTextOption::NoWrap); + qtTextEdit->setHorizontalScrollBarPolicy(wordWrap ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAlwaysOn); + qtTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); +} + +string pTextEdit::text() { + return qtTextEdit->toPlainText().toUtf8().constData(); +} + +void pTextEdit::constructor() { + qtWidget = qtTextEdit = new QTextEdit; + connect(qtTextEdit, SIGNAL(textChanged()), SLOT(onChange())); + + pWidget::synchronizeState(); + setEditable(textEdit.state.editable); + setText(textEdit.state.text); + setWordWrap(textEdit.state.wordWrap); +} + +void pTextEdit::destructor() { + if(sizable.state.layout) sizable.state.layout->remove(textEdit); + delete qtTextEdit; + qtWidget = qtTextEdit = 0; +} + +void pTextEdit::orphan() { + destructor(); + constructor(); +} + +void pTextEdit::onChange() { + textEdit.state.text = text(); + if(textEdit.onChange) textEdit.onChange(); +} diff --git a/kaijuu/phoenix/qt/widget/vertical-scroll-bar.cpp b/kaijuu/phoenix/qt/widget/vertical-scroll-bar.cpp new file mode 100644 index 00000000..74d68ca6 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/vertical-scroll-bar.cpp @@ -0,0 +1,43 @@ +Geometry pVerticalScrollBar::minimumGeometry() { + return { 0, 0, 15, 0 }; +} + +unsigned pVerticalScrollBar::position() { + return qtScrollBar->value(); +} + +void pVerticalScrollBar::setLength(unsigned length) { + length += length == 0; + qtScrollBar->setRange(0, length - 1); + qtScrollBar->setPageStep(length >> 3); +} + +void pVerticalScrollBar::setPosition(unsigned position) { + qtScrollBar->setValue(position); +} + +void pVerticalScrollBar::constructor() { + qtWidget = qtScrollBar = new QScrollBar(Qt::Vertical); + qtScrollBar->setRange(0, 100); + qtScrollBar->setPageStep(101 >> 3); + connect(qtScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::synchronizeState(); + setLength(verticalScrollBar.state.length); + setPosition(verticalScrollBar.state.position); +} + +void pVerticalScrollBar::destructor() { + delete qtScrollBar; + qtWidget = qtScrollBar = 0; +} + +void pVerticalScrollBar::orphan() { + destructor(); + constructor(); +} + +void pVerticalScrollBar::onChange() { + verticalScrollBar.state.position = position(); + if(verticalScrollBar.onChange) verticalScrollBar.onChange(); +} diff --git a/kaijuu/phoenix/qt/widget/vertical-slider.cpp b/kaijuu/phoenix/qt/widget/vertical-slider.cpp new file mode 100644 index 00000000..500adb07 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/vertical-slider.cpp @@ -0,0 +1,43 @@ +Geometry pVerticalSlider::minimumGeometry() { + return { 0, 0, 20, 0 }; +} + +unsigned pVerticalSlider::position() { + return qtSlider->value(); +} + +void pVerticalSlider::setLength(unsigned length) { + length += length == 0; + qtSlider->setRange(0, length - 1); + qtSlider->setPageStep(length >> 3); +} + +void pVerticalSlider::setPosition(unsigned position) { + qtSlider->setValue(position); +} + +void pVerticalSlider::constructor() { + qtWidget = qtSlider = new QSlider(Qt::Vertical); + qtSlider->setRange(0, 100); + qtSlider->setPageStep(101 >> 3); + connect(qtSlider, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::synchronizeState(); + setLength(verticalSlider.state.length); + setPosition(verticalSlider.state.position); +} + +void pVerticalSlider::destructor() { + delete qtSlider; + qtWidget = qtSlider = 0; +} + +void pVerticalSlider::orphan() { + destructor(); + constructor(); +} + +void pVerticalSlider::onChange() { + verticalSlider.state.position = position(); + if(verticalSlider.onChange) verticalSlider.onChange(); +} diff --git a/kaijuu/phoenix/qt/widget/viewport.cpp b/kaijuu/phoenix/qt/widget/viewport.cpp new file mode 100644 index 00000000..1b67d776 --- /dev/null +++ b/kaijuu/phoenix/qt/widget/viewport.cpp @@ -0,0 +1,51 @@ +uintptr_t pViewport::handle() { + return (uintptr_t)qtViewport->winId(); +} + +void pViewport::constructor() { + qtWidget = qtViewport = new QtViewport(*this); + qtViewport->setMouseTracking(true); + qtViewport->setAttribute(Qt::WA_PaintOnScreen, true); + qtViewport->setStyleSheet("background: #000000"); + + pWidget::synchronizeState(); +} + +void pViewport::destructor() { + delete qtViewport; + qtWidget = qtViewport = nullptr; +} + +void pViewport::orphan() { + destructor(); + constructor(); +} + +void pViewport::QtViewport::leaveEvent(QEvent *event) { + if(self.viewport.onMouseLeave) self.viewport.onMouseLeave(); +} + +void pViewport::QtViewport::mouseMoveEvent(QMouseEvent *event) { + if(self.viewport.onMouseMove) self.viewport.onMouseMove({ event->pos().x(), event->pos().y() }); +} + +void pViewport::QtViewport::mousePressEvent(QMouseEvent *event) { + if(self.viewport.onMousePress == false) return; + switch(event->button()) { + case Qt::LeftButton: self.viewport.onMousePress(Mouse::Button::Left); break; + case Qt::MidButton: self.viewport.onMousePress(Mouse::Button::Middle); break; + case Qt::RightButton: self.viewport.onMousePress(Mouse::Button::Right); break; + } +} + +void pViewport::QtViewport::mouseReleaseEvent(QMouseEvent *event) { + if(self.viewport.onMouseRelease == false) return; + switch(event->button()) { + case Qt::LeftButton: self.viewport.onMouseRelease(Mouse::Button::Left); break; + case Qt::MidButton: self.viewport.onMouseRelease(Mouse::Button::Middle); break; + case Qt::RightButton: self.viewport.onMouseRelease(Mouse::Button::Right); break; + } +} + +pViewport::QtViewport::QtViewport(pViewport &self) : self(self) { +} diff --git a/kaijuu/phoenix/qt/widget/widget.cpp b/kaijuu/phoenix/qt/widget/widget.cpp new file mode 100644 index 00000000..0bc4901c --- /dev/null +++ b/kaijuu/phoenix/qt/widget/widget.cpp @@ -0,0 +1,52 @@ +Geometry pWidget::minimumGeometry() { + return { 0, 0, 0, 0 }; +} + +void pWidget::setEnabled(bool enabled) { + if(widget.state.abstract) enabled = false; + if(sizable.state.layout && sizable.state.layout->enabled() == false) enabled = false; + qtWidget->setEnabled(enabled); +} + +void pWidget::setFocused() { + qtWidget->setFocus(Qt::OtherFocusReason); +} + +void pWidget::setFont(const string &font) { + qtWidget->setFont(pFont::create(font)); +} + +void pWidget::setGeometry(const Geometry &geometry) { + qtWidget->setGeometry(geometry.x, geometry.y, geometry.width, geometry.height); +} + +void pWidget::setVisible(bool visible) { + if(widget.state.abstract) visible = false; + if(sizable.state.layout == 0) visible = false; + if(sizable.state.layout && sizable.state.layout->visible() == false) visible = false; + qtWidget->setVisible(visible); +} + +void pWidget::constructor() { + if(widget.state.abstract) qtWidget = new QWidget; +} + +//pWidget::constructor() called before p{Derived}::constructor(); ergo qtWidget is not yet valid +//pWidget::synchronizeState() is called to finish construction of p{Derived}::constructor() +void pWidget::synchronizeState() { + setEnabled(widget.state.enabled); + setFont(widget.state.font); +//setVisible(widget.state.visible); +} + +void pWidget::destructor() { + if(widget.state.abstract) { + delete qtWidget; + qtWidget = 0; + } +} + +void pWidget::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/qt/window.cpp b/kaijuu/phoenix/qt/window.cpp new file mode 100644 index 00000000..c6cb35d6 --- /dev/null +++ b/kaijuu/phoenix/qt/window.cpp @@ -0,0 +1,288 @@ +Window& pWindow::none() { + static Window *window = nullptr; + if(window == nullptr) window = new Window; + return *window; +} + +void pWindow::append(Layout &layout) { + Geometry geometry = window.state.geometry; + geometry.x = geometry.y = 0; + layout.setGeometry(geometry); +} + +void pWindow::append(Menu &menu) { + if(window.state.menuFont != "") menu.p.setFont(window.state.menuFont); + else menu.p.setFont("Sans, 8"); + qtMenu->addMenu(menu.p.qtMenu); +} + +void pWindow::append(Widget &widget) { + if(widget.state.font == "") { + if(window.state.widgetFont != "") widget.p.setFont(window.state.widgetFont); + else widget.p.setFont("Sans, 8"); + } + widget.p.qtWidget->setParent(qtContainer); + widget.setVisible(widget.visible()); +} + +Color pWindow::backgroundColor() { + if(window.state.backgroundColorOverride) return window.state.backgroundColor; + QColor color = qtWindow->palette().color(QPalette::ColorRole::Window); + return { (uint8_t)color.red(), (uint8_t)color.green(), (uint8_t)color.blue(), (uint8_t)color.alpha() }; +} + +Geometry pWindow::frameMargin() { + unsigned menuHeight = window.state.menuVisible ? settings->menuGeometryHeight : 0; + unsigned statusHeight = window.state.statusVisible ? settings->statusGeometryHeight : 0; + if(window.state.fullScreen) return { 0, menuHeight, 0, menuHeight + statusHeight }; + return { + settings->frameGeometryX, + settings->frameGeometryY + menuHeight, + settings->frameGeometryWidth, + settings->frameGeometryHeight + menuHeight + statusHeight + }; +} + +bool pWindow::focused() { + return qtWindow->isActiveWindow() && !qtWindow->isMinimized(); +} + +Geometry pWindow::geometry() { + if(window.state.fullScreen) { + unsigned menuHeight = window.state.menuVisible ? qtMenu->height() : 0; + unsigned statusHeight = window.state.statusVisible ? qtStatus->height() : 0; + return { 0, menuHeight, Desktop::size().width, Desktop::size().height - menuHeight - statusHeight }; + } + return window.state.geometry; +} + +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { + //QMenuBar::removeMenu() does not exist + qtMenu->clear(); + for(auto &menu : window.state.menu) append(menu); +} + +void pWindow::remove(Widget &widget) { + //bugfix: orphan() destroys and recreates widgets (to disassociate them from their parent); + //attempting to create widget again after QApplication::quit() crashes libQtGui + if(qtApplication) widget.p.orphan(); +} + +void pWindow::setBackgroundColor(const Color &color) { + QPalette palette; + palette.setColor(QPalette::Window, QColor(color.red, color.green, color.blue, color.alpha)); + qtContainer->setPalette(palette); + qtContainer->setAutoFillBackground(true); + qtWindow->setAttribute(Qt::WA_TranslucentBackground, color.alpha != 255); +} + +void pWindow::setFocused() { + qtWindow->raise(); + qtWindow->activateWindow(); +} + +void pWindow::setFullScreen(bool fullScreen) { + if(fullScreen == false) { + setResizable(window.state.resizable); + qtWindow->showNormal(); + qtWindow->adjustSize(); + } else { + qtLayout->setSizeConstraint(QLayout::SetDefaultConstraint); + qtContainer->setFixedSize(Desktop::size().width - frameMargin().width, Desktop::size().height - frameMargin().height); + qtWindow->showFullScreen(); + } +} + +void pWindow::setGeometry(const Geometry &geometry_) { + locked = true; + OS::processEvents(); + QApplication::syncX(); + Geometry geometry = geometry_, margin = frameMargin(); + + setResizable(window.state.resizable); + qtWindow->move(geometry.x - frameMargin().x, geometry.y - frameMargin().y); + //qtWindow->adjustSize() fails if larger than 2/3rds screen size + qtWindow->resize(qtWindow->sizeHint()); + qtWindow->setMinimumSize(1, 1); + qtContainer->setMinimumSize(1, 1); + + for(auto &layout : window.state.layout) { + geometry = geometry_; + geometry.x = geometry.y = 0; + layout.setGeometry(geometry); + } + locked = false; +} + +void pWindow::setMenuFont(const string &font) { + qtMenu->setFont(pFont::create(font)); + for(auto &item : window.state.menu) item.p.setFont(font); +} + +void pWindow::setMenuVisible(bool visible) { + qtMenu->setVisible(visible); + setGeometry(window.state.geometry); +} + +void pWindow::setModal(bool modal) { + qtWindow->setWindowModality(modal ? Qt::ApplicationModal : Qt::NonModal); +} + +void pWindow::setResizable(bool resizable) { + if(resizable) { + qtLayout->setSizeConstraint(QLayout::SetDefaultConstraint); + qtContainer->setMinimumSize(window.state.geometry.width, window.state.geometry.height); + } else { + qtLayout->setSizeConstraint(QLayout::SetFixedSize); + qtContainer->setFixedSize(window.state.geometry.width, window.state.geometry.height); + } + qtStatus->setSizeGripEnabled(resizable); +} + +void pWindow::setStatusFont(const string &font) { + qtStatus->setFont(pFont::create(font)); +} + +void pWindow::setStatusText(const string &text) { + qtStatus->showMessage(QString::fromUtf8(text), 0); +} + +void pWindow::setStatusVisible(bool visible) { + qtStatus->setVisible(visible); + setGeometry(window.state.geometry); +} + +void pWindow::setTitle(const string &text) { + qtWindow->setWindowTitle(QString::fromUtf8(text)); +} + +void pWindow::setVisible(bool visible) { + locked = true; + qtWindow->setVisible(visible); + if(visible) { + updateFrameGeometry(); + setGeometry(window.state.geometry); + } + locked = false; +} + +void pWindow::setWidgetFont(const string &font) { + for(auto &item : window.state.widget) { + if(!item.state.font) item.setFont(font); + } +} + +void pWindow::constructor() { + qtWindow = new QtWindow(*this); + qtWindow->setWindowTitle(" "); + + qtLayout = new QVBoxLayout(qtWindow); + qtLayout->setMargin(0); + qtLayout->setSpacing(0); + qtWindow->setLayout(qtLayout); + + qtMenu = new QMenuBar(qtWindow); + qtMenu->setVisible(false); + qtLayout->addWidget(qtMenu); + + qtContainer = new QWidget(qtWindow); + qtContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + qtContainer->setVisible(true); + qtLayout->addWidget(qtContainer); + + qtStatus = new QStatusBar(qtWindow); + qtStatus->setSizeGripEnabled(true); + qtStatus->setVisible(false); + qtLayout->addWidget(qtStatus); + + setGeometry(window.state.geometry); + setMenuFont("Sans, 8"); + setStatusFont("Sans, 8"); +} + +void pWindow::destructor() { + delete qtStatus; + delete qtContainer; + delete qtMenu; + delete qtLayout; + delete qtWindow; +} + +void pWindow::updateFrameGeometry() { + pOS::syncX(); + QRect border = qtWindow->frameGeometry(); + QRect client = qtWindow->geometry(); + + settings->frameGeometryX = client.x() - border.x(); + settings->frameGeometryY = client.y() - border.y(); + settings->frameGeometryWidth = border.width() - client.width(); + settings->frameGeometryHeight = border.height() - client.height(); + + if(window.state.menuVisible) { + pOS::syncX(); + settings->menuGeometryHeight = qtMenu->height(); + } + + if(window.state.statusVisible) { + pOS::syncX(); + settings->statusGeometryHeight = qtStatus->height(); + } + + settings->save(); +} + +void pWindow::QtWindow::closeEvent(QCloseEvent *event) { + self.window.state.ignore = false; + event->ignore(); + if(self.window.onClose) self.window.onClose(); + if(self.window.state.ignore == false) hide(); +} + +void pWindow::QtWindow::moveEvent(QMoveEvent *event) { + if(self.locked == false && self.window.state.fullScreen == false && self.qtWindow->isVisible() == true) { + self.window.state.geometry.x += event->pos().x() - event->oldPos().x(); + self.window.state.geometry.y += event->pos().y() - event->oldPos().y(); + } + + if(self.locked == false) { + if(self.window.onMove) self.window.onMove(); + } +} + +void pWindow::QtWindow::keyPressEvent(QKeyEvent *event) { + Keyboard::Keycode sym = Keysym(event->nativeVirtualKey()); + if(sym != Keyboard::Keycode::None && self.window.onKeyPress) self.window.onKeyPress(sym); +} + +void pWindow::QtWindow::keyReleaseEvent(QKeyEvent *event) { + Keyboard::Keycode sym = Keysym(event->nativeVirtualKey()); + if(sym != Keyboard::Keycode::None && self.window.onKeyRelease) self.window.onKeyRelease(sym); +} + +void pWindow::QtWindow::resizeEvent(QResizeEvent*) { + if(self.locked == false && self.window.state.fullScreen == false && self.qtWindow->isVisible() == true) { + self.window.state.geometry.width = self.qtContainer->geometry().width(); + self.window.state.geometry.height = self.qtContainer->geometry().height(); + } + + for(auto &layout : self.window.state.layout) { + Geometry geometry = self.geometry(); + geometry.x = geometry.y = 0; + layout.setGeometry(geometry); + } + + if(self.locked == false) { + if(self.window.onSize) self.window.onSize(); + } +} + +QSize pWindow::QtWindow::sizeHint() const { + unsigned width = self.window.state.geometry.width; + unsigned height = self.window.state.geometry.height; + if(self.window.state.menuVisible) height += settings->menuGeometryHeight; + if(self.window.state.statusVisible) height += settings->statusGeometryHeight; + return QSize(width, height); +} diff --git a/kaijuu/phoenix/reference/action/action.cpp b/kaijuu/phoenix/reference/action/action.cpp new file mode 100644 index 00000000..0bc6bc3f --- /dev/null +++ b/kaijuu/phoenix/reference/action/action.cpp @@ -0,0 +1,8 @@ +void pAction::setEnabled(bool enabled) { +} + +void pAction::setVisible(bool visible) { +} + +void pAction::constructor() { +} diff --git a/kaijuu/phoenix/reference/action/check-item.cpp b/kaijuu/phoenix/reference/action/check-item.cpp new file mode 100644 index 00000000..26970fc8 --- /dev/null +++ b/kaijuu/phoenix/reference/action/check-item.cpp @@ -0,0 +1,15 @@ +bool pCheckItem::checked() { + return false; +} + +void pCheckItem::setChecked(bool checked) { +} + +void pCheckItem::setText(const string &text) { +} + +void pCheckItem::constructor() { +} + +void pCheckItem::destructor() { +} diff --git a/kaijuu/phoenix/reference/action/item.cpp b/kaijuu/phoenix/reference/action/item.cpp new file mode 100644 index 00000000..438ed32f --- /dev/null +++ b/kaijuu/phoenix/reference/action/item.cpp @@ -0,0 +1,11 @@ +void pItem::setImage(const image &image) { +} + +void pItem::setText(const string &text) { +} + +void pItem::constructor() { +} + +void pItem::destructor() { +} diff --git a/kaijuu/phoenix/reference/action/menu.cpp b/kaijuu/phoenix/reference/action/menu.cpp new file mode 100644 index 00000000..4f0a65a8 --- /dev/null +++ b/kaijuu/phoenix/reference/action/menu.cpp @@ -0,0 +1,17 @@ +void pMenu::append(Action &action) { +} + +void pMenu::remove(Action &action) { +} + +void pMenu::setImage(const image &image) { +} + +void pMenu::setText(const string &text) { +} + +void pMenu::constructor() { +} + +void pMenu::destructor() { +} diff --git a/kaijuu/phoenix/reference/action/radio-item.cpp b/kaijuu/phoenix/reference/action/radio-item.cpp new file mode 100644 index 00000000..e87a4deb --- /dev/null +++ b/kaijuu/phoenix/reference/action/radio-item.cpp @@ -0,0 +1,18 @@ +bool pRadioItem::checked() { + return false; +} + +void pRadioItem::setChecked() { +} + +void pRadioItem::setGroup(const set &group) { +} + +void pRadioItem::setText(const string &text) { +} + +void pRadioItem::constructor() { +} + +void pRadioItem::destructor() { +} diff --git a/kaijuu/phoenix/reference/action/separator.cpp b/kaijuu/phoenix/reference/action/separator.cpp new file mode 100644 index 00000000..24a45c04 --- /dev/null +++ b/kaijuu/phoenix/reference/action/separator.cpp @@ -0,0 +1,5 @@ +void pSeparator::constructor() { +} + +void pSeparator::destructor() { +} diff --git a/kaijuu/phoenix/reference/desktop.cpp b/kaijuu/phoenix/reference/desktop.cpp new file mode 100644 index 00000000..a96eb1f0 --- /dev/null +++ b/kaijuu/phoenix/reference/desktop.cpp @@ -0,0 +1,8 @@ +Size pDesktop::size() { + return { 0, 0 }; +} + +Geometry pDesktop::workspace() { + return { 0, 0, 0, 0 }; +} + diff --git a/kaijuu/phoenix/reference/dialog-window.cpp b/kaijuu/phoenix/reference/dialog-window.cpp new file mode 100644 index 00000000..c7d089ae --- /dev/null +++ b/kaijuu/phoenix/reference/dialog-window.cpp @@ -0,0 +1,11 @@ +string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) { + return ""; +} + +string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) { + return ""; +} + +string pDialogWindow::folderSelect(Window &parent, const string &path) { + return ""; +} diff --git a/kaijuu/phoenix/reference/font.cpp b/kaijuu/phoenix/reference/font.cpp new file mode 100644 index 00000000..bfda5c06 --- /dev/null +++ b/kaijuu/phoenix/reference/font.cpp @@ -0,0 +1,3 @@ +Geometry pFont::geometry(const string &description, const string &text) { + return { 0, 0, 0, 0 }; +} diff --git a/kaijuu/phoenix/reference/keyboard.cpp b/kaijuu/phoenix/reference/keyboard.cpp new file mode 100644 index 00000000..40b3a1a7 --- /dev/null +++ b/kaijuu/phoenix/reference/keyboard.cpp @@ -0,0 +1,10 @@ +bool pKeyboard::pressed(Keyboard::Scancode scancode) { + return false; +} + +vector pKeyboard::state() { + vector output; + output.resize((unsigned)Keyboard::Scancode::Limit); + for(auto &n : output) n = false; + return output; +} diff --git a/kaijuu/phoenix/reference/message-window.cpp b/kaijuu/phoenix/reference/message-window.cpp new file mode 100644 index 00000000..84a287f5 --- /dev/null +++ b/kaijuu/phoenix/reference/message-window.cpp @@ -0,0 +1,15 @@ +MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow::Response::Ok; +} diff --git a/kaijuu/phoenix/reference/mouse.cpp b/kaijuu/phoenix/reference/mouse.cpp new file mode 100644 index 00000000..f103a15a --- /dev/null +++ b/kaijuu/phoenix/reference/mouse.cpp @@ -0,0 +1,7 @@ +Position pMouse::position() { + return { 0, 0 }; +} + +bool pMouse::pressed(Mouse::Button button) { + return false; +} diff --git a/kaijuu/phoenix/reference/platform.cpp b/kaijuu/phoenix/reference/platform.cpp new file mode 100644 index 00000000..e64f7eab --- /dev/null +++ b/kaijuu/phoenix/reference/platform.cpp @@ -0,0 +1,52 @@ +#include "platform.hpp" + +#include "desktop.cpp" +#include "keyboard.cpp" +#include "mouse.cpp" +#include "dialog-window.cpp" +#include "message-window.cpp" + +#include "font.cpp" +#include "timer.cpp" +#include "window.cpp" + +#include "action/action.cpp" +#include "action/menu.cpp" +#include "action/separator.cpp" +#include "action/item.cpp" +#include "action/check-item.cpp" +#include "action/radio-item.cpp" + +#include "widget/widget.cpp" +#include "widget/button.cpp" +#include "widget/canvas.cpp" +#include "widget/check-box.cpp" +#include "widget/combo-box.cpp" +#include "widget/hex-edit.cpp" +#include "widget/horizontal-scroll-bar.cpp" +#include "widget/horizontal-slider.cpp" +#include "widget/label.cpp" +#include "widget/line-edit.cpp" +#include "widget/list-view.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-box.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +void pOS::main() { +} + +bool pOS::pendingEvents() { + return false; +} + +void pOS::processEvents() { +} + +void pOS::quit() { +} + +void pOS::initialize() { +} diff --git a/kaijuu/phoenix/reference/platform.hpp b/kaijuu/phoenix/reference/platform.hpp new file mode 100644 index 00000000..5ffb5b60 --- /dev/null +++ b/kaijuu/phoenix/reference/platform.hpp @@ -0,0 +1,381 @@ +struct pFont; +struct pWindow; +struct pMenu; +struct pLayout; +struct pWidget; + +struct pFont { + static Geometry geometry(const string &description, const string &text); +}; + +struct pDesktop { + static Size size(); + static Geometry workspace(); +}; + +struct pKeyboard { + static bool pressed(Keyboard::Scancode scancode); + static vector state(); +}; + +struct pMouse { + static Position position(); + static bool pressed(Mouse::Button button); +}; + +struct pDialogWindow { + static string fileOpen(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); +}; + +struct pMessageWindow { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + +struct pObject { + Object &object; + bool locked; + + pObject(Object &object) : object(object), locked(locked) {} + virtual ~pObject() {} + + void constructor() {} + void destructor() {} +}; + +struct pOS : public pObject { + static void main(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + static void initialize(); +}; + +struct pTimer : public pObject { + Timer &timer; + + void setEnabled(bool enabled); + void setInterval(unsigned milliseconds); + + pTimer(Timer &timer) : pObject(timer), timer(timer) {} + void constructor(); +}; + +struct pWindow : public pObject { + Window &window; + + void append(Layout &layout); + void append(Menu &menu); + void append(Widget &widget); + Color backgroundColor(); + bool focused(); + Geometry frameMargin(); + Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); + void setBackgroundColor(const Color &color); + void setFocused(); + void setFullScreen(bool fullScreen); + void setGeometry(const Geometry &geometry); + void setMenuFont(const string &font); + void setMenuVisible(bool visible); + void setModal(bool modal); + void setResizable(bool resizable); + void setStatusFont(const string &font); + void setStatusText(const string &text); + void setStatusVisible(bool visible); + void setTitle(const string &text); + void setVisible(bool visible); + void setWidgetFont(const string &font); + + pWindow(Window &window) : pObject(window), window(window) {} + void constructor(); +}; + +struct pAction : public pObject { + Action &action; + + void setEnabled(bool enabled); + void setVisible(bool visible); + + pAction(Action &action) : pObject(action), action(action) {} + void constructor(); +}; + +struct pMenu : public pAction { + Menu &menu; + + void append(Action &action); + void remove(Action &action); + void setImage(const image &image); + void setText(const string &text); + + pMenu(Menu &menu) : pAction(menu), menu(menu) {} + void constructor(); + void destructor(); +}; + +struct pSeparator : public pAction { + Separator &separator; + + pSeparator(Separator &separator) : pAction(separator), separator(separator) {} + void constructor(); + void destructor(); +}; + +struct pItem : public pAction { + Item &item; + + void setImage(const image &image); + void setText(const string &text); + + pItem(Item &item) : pAction(item), item(item) {} + void constructor(); + void destructor(); +}; + +struct pCheckItem : public pAction { + CheckItem &checkItem; + + bool checked(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} + void constructor(); + void destructor(); +}; + +struct pRadioItem : public pAction { + RadioItem &radioItem; + + bool checked(); + void setChecked(); + void setGroup(const set &group); + void setText(const string &text); + + pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} + void constructor(); + void destructor(); +}; + +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} +}; + +struct pWidget : public pSizable { + Widget &widget; + + bool enabled(); + Geometry minimumGeometry(); + void setEnabled(bool enabled); + void setFocused(); + void setFont(const string &font); + void setGeometry(const Geometry &geometry); + void setVisible(bool visible); + + pWidget(Widget &widget) : pSizable(widget), widget(widget) {} + void constructor(); +}; + +struct pButton : public pWidget { + Button &button; + + void setImage(const image &image, Orientation orientation); + void setText(const string &text); + + pButton(Button &button) : pWidget(button), button(button) {} + void constructor(); +}; + +struct pCanvas : public pWidget { + Canvas &canvas; + + void setSize(const Size &size); + void update(); + + pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} + void constructor(); +}; + +struct pCheckBox : public pWidget { + CheckBox &checkBox; + + bool checked(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckBox(CheckBox &checkBox) : pWidget(checkBox), checkBox(checkBox) {} + void constructor(); +}; + +struct pComboBox : public pWidget { + ComboBox &comboBox; + + void append(const string &text); + void modify(unsigned row, const string &text); + void remove(unsigned row); + void reset(); + unsigned selection(); + void setSelection(unsigned row); + + pComboBox(ComboBox &comboBox) : pWidget(comboBox), comboBox(comboBox) {} + void constructor(); +}; + +struct pHexEdit : public pWidget { + HexEdit &hexEdit; + + void setColumns(unsigned columns); + void setLength(unsigned length); + void setOffset(unsigned offset); + void setRows(unsigned rows); + void update(); + + pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} + void constructor(); +}; + +struct pHorizontalScrollBar : public pWidget { + HorizontalScrollBar &horizontalScrollBar; + + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {} + void constructor(); +}; + +struct pHorizontalSlider : public pWidget { + HorizontalSlider &horizontalSlider; + + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalSlider(HorizontalSlider &horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} + void constructor(); +}; + +struct pLabel : public pWidget { + Label &label; + + void setText(const string &text); + + pLabel(Label &label) : pWidget(label), label(label) {} + void constructor(); +}; + +struct pLineEdit : public pWidget { + LineEdit &lineEdit; + + void setEditable(bool editable); + void setText(const string &text); + string text(); + + pLineEdit(LineEdit &lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} + void constructor(); +}; + +struct pListView : public pWidget { + ListView &listView; + + void append(const lstring &text); + void autoSizeColumns(); + bool checked(unsigned row); + void modify(unsigned row, const lstring &text); + void remove(unsigned row); + void reset(); + bool selected(); + unsigned selection(); + void setCheckable(bool checkable); + void setChecked(unsigned row, bool checked); + void setHeaderText(const lstring &text); + void setHeaderVisible(bool visible); + void setImage(unsigned row, unsigned column, const image &image); + void setSelected(bool selected); + void setSelection(unsigned row); + + pListView(ListView &listView) : pWidget(listView), listView(listView) {} + void constructor(); +}; + +struct pProgressBar : public pWidget { + ProgressBar &progressBar; + + void setPosition(unsigned position); + + pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {} + void constructor(); +}; + +struct pRadioBox : public pWidget { + RadioBox &radioBox; + + bool checked(); + void setChecked(); + void setGroup(const set &group); + void setText(const string &text); + + pRadioBox(RadioBox &radioBox) : pWidget(radioBox), radioBox(radioBox) {} + void constructor(); +}; + +struct pTextEdit : public pWidget { + TextEdit &textEdit; + + void setCursorPosition(unsigned position); + void setEditable(bool editable); + void setText(const string &text); + void setWordWrap(bool wordWrap); + string text(); + + pTextEdit(TextEdit &textEdit) : pWidget(textEdit), textEdit(textEdit) {} + void constructor(); +}; + +struct pVerticalScrollBar : public pWidget { + VerticalScrollBar &verticalScrollBar; + + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {} + void constructor(); +}; + +struct pVerticalSlider : public pWidget { + VerticalSlider &verticalSlider; + + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalSlider(VerticalSlider &verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} + void constructor(); +}; + +struct pViewport : public pWidget { + Viewport &viewport; + + uintptr_t handle(); + + pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} + void constructor(); +}; diff --git a/kaijuu/phoenix/reference/timer.cpp b/kaijuu/phoenix/reference/timer.cpp new file mode 100644 index 00000000..6cbe571a --- /dev/null +++ b/kaijuu/phoenix/reference/timer.cpp @@ -0,0 +1,8 @@ +void pTimer::setEnabled(bool enabled) { +} + +void pTimer::setInterval(unsigned milliseconds) { +} + +void pTimer::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/button.cpp b/kaijuu/phoenix/reference/widget/button.cpp new file mode 100644 index 00000000..fc06c371 --- /dev/null +++ b/kaijuu/phoenix/reference/widget/button.cpp @@ -0,0 +1,8 @@ +void pButton::setImage(const image &image, Orientation orientation) { +} + +void pButton::setText(const string &text) { +} + +void pButton::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/canvas.cpp b/kaijuu/phoenix/reference/widget/canvas.cpp new file mode 100644 index 00000000..953cfa77 --- /dev/null +++ b/kaijuu/phoenix/reference/widget/canvas.cpp @@ -0,0 +1,8 @@ +void pCanvas::setSize(const Size &size) { +} + +void pCanvas::update() { +} + +void pCanvas::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/check-box.cpp b/kaijuu/phoenix/reference/widget/check-box.cpp new file mode 100644 index 00000000..c5aec216 --- /dev/null +++ b/kaijuu/phoenix/reference/widget/check-box.cpp @@ -0,0 +1,12 @@ +bool pCheckBox::checked() { + return false; +} + +void pCheckBox::setChecked(bool checked) { +} + +void pCheckBox::setText(const string &text) { +} + +void pCheckBox::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/combo-box.cpp b/kaijuu/phoenix/reference/widget/combo-box.cpp new file mode 100644 index 00000000..297d7369 --- /dev/null +++ b/kaijuu/phoenix/reference/widget/combo-box.cpp @@ -0,0 +1,21 @@ +void pComboBox::append(const string &text) { +} + +void pComboBox::modify(unsigned row, const string &text) { +} + +void pComboBox::remove(unsigned row) { +} + +void pComboBox::reset() { +} + +unsigned pComboBox::selection() { + return 0; +} + +void pComboBox::setSelection(unsigned row) { +} + +void pComboBox::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/hex-edit.cpp b/kaijuu/phoenix/reference/widget/hex-edit.cpp new file mode 100644 index 00000000..40bf9f5d --- /dev/null +++ b/kaijuu/phoenix/reference/widget/hex-edit.cpp @@ -0,0 +1,17 @@ +void pHexEdit::setColumns(unsigned columns) { +} + +void pHexEdit::setLength(unsigned length) { +} + +void pHexEdit::setOffset(unsigned offset) { +} + +void pHexEdit::setRows(unsigned rows) { +} + +void pHexEdit::update() { +} + +void pHexEdit::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/horizontal-scroll-bar.cpp b/kaijuu/phoenix/reference/widget/horizontal-scroll-bar.cpp new file mode 100644 index 00000000..352b3393 --- /dev/null +++ b/kaijuu/phoenix/reference/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,12 @@ +unsigned pHorizontalScrollBar::position() { + return 0; +} + +void pHorizontalScrollBar::setLength(unsigned length) { +} + +void pHorizontalScrollBar::setPosition(unsigned position) { +} + +void pHorizontalScrollBar::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/horizontal-slider.cpp b/kaijuu/phoenix/reference/widget/horizontal-slider.cpp new file mode 100644 index 00000000..0a4a8392 --- /dev/null +++ b/kaijuu/phoenix/reference/widget/horizontal-slider.cpp @@ -0,0 +1,12 @@ +unsigned pHorizontalSlider::position() { + return 0; +} + +void pHorizontalSlider::setLength(unsigned length) { +} + +void pHorizontalSlider::setPosition(unsigned position) { +} + +void pHorizontalSlider::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/label.cpp b/kaijuu/phoenix/reference/widget/label.cpp new file mode 100644 index 00000000..25600d2a --- /dev/null +++ b/kaijuu/phoenix/reference/widget/label.cpp @@ -0,0 +1,5 @@ +void pLabel::setText(const string &text) { +} + +void pLabel::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/line-edit.cpp b/kaijuu/phoenix/reference/widget/line-edit.cpp new file mode 100644 index 00000000..96b9ac6c --- /dev/null +++ b/kaijuu/phoenix/reference/widget/line-edit.cpp @@ -0,0 +1,11 @@ +void pLineEdit::setEditable(bool editable) { +} + +void pLineEdit::setText(const string &text) { +} + +string pLineEdit::text() { +} + +void pLineEdit::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/list-view.cpp b/kaijuu/phoenix/reference/widget/list-view.cpp new file mode 100644 index 00000000..6e90e0a3 --- /dev/null +++ b/kaijuu/phoenix/reference/widget/list-view.cpp @@ -0,0 +1,49 @@ +void pListView::append(const lstring &text) { +} + +void pListView::autoSizeColumns() { +} + +bool pListView::checked(unsigned row) { +} + +void pListView::modify(unsigned row, const lstring &text) { +} + +void pListView::remove(unsigned row) { +} + +void pListView::reset() { +} + +bool pListView::selected() { + return false; +} + +unsigned pListView::selection() { + return 0; +} + +void pListView::setCheckable(bool checkable) { +} + +void pListView::setChecked(unsigned row, bool checked) { +} + +void pListView::setHeaderText(const lstring &text) { +} + +void pListView::setHeaderVisible(bool visible) { +} + +void pListView::setImage(unsigned row, unsigned column, const image &image) { +} + +void pListView::setSelected(bool selected) { +} + +void pListView::setSelection(unsigned row) { +} + +void pListView::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/progress-bar.cpp b/kaijuu/phoenix/reference/widget/progress-bar.cpp new file mode 100644 index 00000000..b4905a85 --- /dev/null +++ b/kaijuu/phoenix/reference/widget/progress-bar.cpp @@ -0,0 +1,5 @@ +void pProgressBar::setPosition(unsigned position) { +} + +void pProgressBar::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/radio-box.cpp b/kaijuu/phoenix/reference/widget/radio-box.cpp new file mode 100644 index 00000000..f6aebcbe --- /dev/null +++ b/kaijuu/phoenix/reference/widget/radio-box.cpp @@ -0,0 +1,15 @@ +bool pRadioBox::checked() { + return false; +} + +void pRadioBox::setChecked() { +} + +void pRadioBox::setGroup(const set &group) { +} + +void pRadioBox::setText(const string &text) { +} + +void pRadioBox::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/text-edit.cpp b/kaijuu/phoenix/reference/widget/text-edit.cpp new file mode 100644 index 00000000..74121b2d --- /dev/null +++ b/kaijuu/phoenix/reference/widget/text-edit.cpp @@ -0,0 +1,17 @@ +void pTextEdit::setCursorPosition(unsigned position) { +} + +void pTextEdit::setEditable(bool editable) { +} + +void pTextEdit::setText(const string &text) { +} + +void pTextEdit::setWordWrap(bool wordWrap) { +} + +string pTextEdit::text() { +} + +void pTextEdit::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/vertical-scroll-bar.cpp b/kaijuu/phoenix/reference/widget/vertical-scroll-bar.cpp new file mode 100644 index 00000000..26795248 --- /dev/null +++ b/kaijuu/phoenix/reference/widget/vertical-scroll-bar.cpp @@ -0,0 +1,12 @@ +unsigned pVerticalScrollBar::position() { + return 0; +} + +void pVerticalScrollBar::setLength(unsigned length) { +} + +void pVerticalScrollBar::setPosition(unsigned position) { +} + +void pVerticalScrollBar::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/vertical-slider.cpp b/kaijuu/phoenix/reference/widget/vertical-slider.cpp new file mode 100644 index 00000000..a6d8ae00 --- /dev/null +++ b/kaijuu/phoenix/reference/widget/vertical-slider.cpp @@ -0,0 +1,12 @@ +unsigned pVerticalSlider::position() { + return 0; +} + +void pVerticalSlider::setLength(unsigned length) { +} + +void pVerticalSlider::setPosition(unsigned position) { +} + +void pVerticalSlider::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/viewport.cpp b/kaijuu/phoenix/reference/widget/viewport.cpp new file mode 100644 index 00000000..9d398438 --- /dev/null +++ b/kaijuu/phoenix/reference/widget/viewport.cpp @@ -0,0 +1,6 @@ +uintptr_t pViewport::handle() { + return 0; +} + +void pViewport::constructor() { +} diff --git a/kaijuu/phoenix/reference/widget/widget.cpp b/kaijuu/phoenix/reference/widget/widget.cpp new file mode 100644 index 00000000..49a6c79e --- /dev/null +++ b/kaijuu/phoenix/reference/widget/widget.cpp @@ -0,0 +1,25 @@ +bool pWidget::enabled() { + return false; +} + +Geometry pWidget::minimumGeometry() { + return { 0, 0, 0, 0 }; +} + +void pWidget::setEnabled(bool enabled) { +} + +void pWidget::setFocused() { +} + +void pWidget::setFont(const string &font) { +} + +void pWidget::setGeometry(const Geometry &geometry) { +} + +void pWidget::setVisible(bool visible) { +} + +void pWidget::constructor() { +} diff --git a/kaijuu/phoenix/reference/window.cpp b/kaijuu/phoenix/reference/window.cpp new file mode 100644 index 00000000..128a9c2d --- /dev/null +++ b/kaijuu/phoenix/reference/window.cpp @@ -0,0 +1,78 @@ +void pWindow::append(Layout &layout) { +} + +void pWindow::append(Menu &menu) { +} + +void pWindow::append(Widget &widget) { +} + +Color pWindow::backgroundColor() { + return {0, 0, 0, 255}; +} + +bool pWindow::focused() { + return false; +} + +Geometry pWindow::frameMargin() { + return {0, 0, 0, 0}; +} + +Geometry pWindow::geometry() { + return {0, 0, 0, 0}; +} + +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { +} + +void pWindow::remove(Widget &widget) { +} + +void pWindow::setBackgroundColor(const Color &color) { +} + +void pWindow::setFocused() { +} + +void pWindow::setFullScreen(bool fullScreen) { +} + +void pWindow::setGeometry(const Geometry &geometry) { +} + +void pWindow::setMenuFont(const string &font) { +} + +void pWindow::setMenuVisible(bool visible) { +} + +void pWindow::setModal(bool modal) { +} + +void pWindow::setResizable(bool resizable) { +} + +void pWindow::setStatusFont(const string &font) { +} + +void pWindow::setStatusText(const string &text) { +} + +void pWindow::setStatusVisible(bool visible) { +} + +void pWindow::setTitle(const string &text) { +} + +void pWindow::setVisible(bool visible) { +} + +void pWindow::setWidgetFont(const string &font) { +} + +void pWindow::constructor() { +} diff --git a/snesfilter/sync.sh b/kaijuu/phoenix/sync.sh old mode 100755 new mode 100644 similarity index 88% rename from snesfilter/sync.sh rename to kaijuu/phoenix/sync.sh index b51e3b40..40ee3d98 --- a/snesfilter/sync.sh +++ b/kaijuu/phoenix/sync.sh @@ -6,3 +6,4 @@ synchronize() { } synchronize "nall" +rm -r nall/test diff --git a/kaijuu/phoenix/windows/action/action.cpp b/kaijuu/phoenix/windows/action/action.cpp new file mode 100644 index 00000000..b80208d1 --- /dev/null +++ b/kaijuu/phoenix/windows/action/action.cpp @@ -0,0 +1,12 @@ +void pAction::setEnabled(bool enabled) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pAction::setVisible(bool visible) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pAction::constructor() { + parentMenu = 0; + parentWindow = 0; +} diff --git a/kaijuu/phoenix/windows/action/check-item.cpp b/kaijuu/phoenix/windows/action/check-item.cpp new file mode 100644 index 00000000..195deabd --- /dev/null +++ b/kaijuu/phoenix/windows/action/check-item.cpp @@ -0,0 +1,18 @@ +bool pCheckItem::checked() { + return checkItem.state.checked; +} + +void pCheckItem::setChecked(bool checked) { + if(parentMenu) CheckMenuItem(parentMenu->p.hmenu, id, checked ? MF_CHECKED : MF_UNCHECKED); +} + +void pCheckItem::setText(const string &text) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pCheckItem::constructor() { +} + +void pCheckItem::destructor() { + if(parentMenu) parentMenu->remove(checkItem); +} diff --git a/kaijuu/phoenix/windows/action/item.cpp b/kaijuu/phoenix/windows/action/item.cpp new file mode 100644 index 00000000..2804bfcb --- /dev/null +++ b/kaijuu/phoenix/windows/action/item.cpp @@ -0,0 +1,29 @@ +void pItem::setImage(const image &image) { + createBitmap(); + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pItem::setText(const string &text) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pItem::constructor() { + createBitmap(); +} + +void pItem::destructor() { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } + if(parentMenu) parentMenu->remove(item); +} + +void pItem::createBitmap() { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } + + if(item.state.image.width && item.state.image.height) { + nall::image nallImage = item.state.image; + nallImage.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + nallImage.alphaBlend(GetSysColor(COLOR_MENU)); //Windows does not alpha blend menu icons properly (leaves black outline) + nallImage.scale(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK), Interpolation::Linear); + hbitmap = CreateBitmap(nallImage); + } +} diff --git a/kaijuu/phoenix/windows/action/menu.cpp b/kaijuu/phoenix/windows/action/menu.cpp new file mode 100644 index 00000000..5d9da04e --- /dev/null +++ b/kaijuu/phoenix/windows/action/menu.cpp @@ -0,0 +1,109 @@ +void pMenu::append(Action &action) { + action.p.parentMenu = &menu; + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pMenu::remove(Action &action) { + if(parentWindow) parentWindow->p.updateMenu(); + action.p.parentMenu = 0; +} + +void pMenu::setImage(const image &image) { + createBitmap(); + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pMenu::setText(const string &text) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pMenu::constructor() { + hmenu = 0; + createBitmap(); +} + +void pMenu::destructor() { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } + if(parentMenu) { + parentMenu->remove(menu); + } else if(parentWindow) { + //belongs to window's main menubar + parentWindow->remove(menu); + } +} + +void pMenu::createBitmap() { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } + + if(menu.state.image.width && menu.state.image.height) { + nall::image nallImage = menu.state.image; + nallImage.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + nallImage.alphaBlend(GetSysColor(COLOR_MENU)); //Windows does not alpha blend menu icons properly (leaves black outline) + nallImage.scale(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK), Interpolation::Linear); + hbitmap = CreateBitmap(nallImage); + } +} + +//Windows actions lack the ability to toggle visibility. +//To support this, menus must be destroyed and recreated when toggling any action's visibility. +void pMenu::update(Window &parentWindow, Menu *parentMenu) { + this->parentMenu = parentMenu; + this->parentWindow = &parentWindow; + + if(hmenu) DestroyMenu(hmenu); + hmenu = CreatePopupMenu(); + + for(auto &action : menu.state.action) { + action.p.parentMenu = &menu; + action.p.parentWindow = &parentWindow; + + unsigned enabled = action.state.enabled ? 0 : MF_GRAYED; + if(dynamic_cast(&action)) { + Menu &item = (Menu&)action; + if(action.state.visible) { + item.p.update(parentWindow, &menu); + AppendMenu(hmenu, MF_STRING | MF_POPUP | enabled, (UINT_PTR)item.p.hmenu, utf16_t(item.state.text)); + + if(item.state.image.width && item.state.image.height) { + MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; + //Windows XP and below displays MIIM_BITMAP + hbmpItem in its own column (separate from check/radio marks) + //this causes too much spacing, so use a custom checkmark image instead + mii.fMask = MIIM_CHECKMARKS; + mii.hbmpUnchecked = item.p.hbitmap; + SetMenuItemInfo(hmenu, (UINT_PTR)item.p.hmenu, FALSE, &mii); + } + } + } else if(dynamic_cast(&action)) { + Separator &item = (Separator&)action; + if(action.state.visible) { + AppendMenu(hmenu, MF_SEPARATOR | enabled, item.p.id, L""); + } + } else if(dynamic_cast(&action)) { + Item &item = (Item&)action; + if(action.state.visible) { + AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text)); + + if(item.state.image.width && item.state.image.height) { + MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; + //Windows XP and below displays MIIM_BITMAP + hbmpItem in its own column (separate from check/radio marks) + //this causes too much spacing, so use a custom checkmark image instead + mii.fMask = MIIM_CHECKMARKS; + mii.hbmpUnchecked = item.p.hbitmap; + SetMenuItemInfo(hmenu, item.p.id, FALSE, &mii); + } + } + } else if(dynamic_cast(&action)) { + CheckItem &item = (CheckItem&)action; + if(action.state.visible) { + AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text)); + } + if(item.state.checked) item.setChecked(); + } else if(dynamic_cast(&action)) { + RadioItem &item = (RadioItem&)action; + if(action.state.visible) { + AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text)); + } + if(item.state.checked) item.setChecked(); + } + } +} diff --git a/kaijuu/phoenix/windows/action/radio-item.cpp b/kaijuu/phoenix/windows/action/radio-item.cpp new file mode 100644 index 00000000..6b4f3a31 --- /dev/null +++ b/kaijuu/phoenix/windows/action/radio-item.cpp @@ -0,0 +1,26 @@ +bool pRadioItem::checked() { + return radioItem.state.checked; +} + +void pRadioItem::setChecked() { + for(auto &item : radioItem.state.group) { + //CheckMenuRadioItem takes: lo, hi, id; checking only id when lo <= id <= hi + //phoenix does not force IDs to be linear, so to uncheck id, we use: lo == hi == id + 1 (out of range) + //to check id, we use: lo == hi == id (only ID, but in range) + if(item.p.parentMenu) CheckMenuRadioItem(item.p.parentMenu->p.hmenu, item.p.id, item.p.id, item.p.id + (id != item.p.id), MF_BYCOMMAND); + } +} + +void pRadioItem::setGroup(const set &group) { +} + +void pRadioItem::setText(const string &text) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pRadioItem::constructor() { +} + +void pRadioItem::destructor() { + if(parentMenu) parentMenu->remove(radioItem); +} diff --git a/kaijuu/phoenix/windows/action/separator.cpp b/kaijuu/phoenix/windows/action/separator.cpp new file mode 100644 index 00000000..fac38eca --- /dev/null +++ b/kaijuu/phoenix/windows/action/separator.cpp @@ -0,0 +1,6 @@ +void pSeparator::constructor() { +} + +void pSeparator::destructor() { + if(parentMenu) parentMenu->remove(separator); +} diff --git a/kaijuu/phoenix/windows/desktop.cpp b/kaijuu/phoenix/windows/desktop.cpp new file mode 100644 index 00000000..956ba521 --- /dev/null +++ b/kaijuu/phoenix/windows/desktop.cpp @@ -0,0 +1,9 @@ +Size pDesktop::size() { + return { GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) }; +} + +Geometry pDesktop::workspace() { + RECT rc; + SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); + return { rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top }; +} diff --git a/kaijuu/phoenix/windows/dialog-window.cpp b/kaijuu/phoenix/windows/dialog-window.cpp new file mode 100644 index 00000000..3005c020 --- /dev/null +++ b/kaijuu/phoenix/windows/dialog-window.cpp @@ -0,0 +1,88 @@ +static string FileDialog(bool save, Window &parent, const string &path, const lstring &filter) { + string dir = path; + dir.replace("/", "\\"); + + string filterList; + for(auto &filterItem : filter) { + lstring part; + part.split("(", filterItem); + if(part.size() != 2) continue; + part[1].rtrim<1>(")"); + part[1].replace(" ", ""); + part[1].transform(",", ";"); + filterList.append(string(filterItem, "\t", part[1], "\t")); + } + + utf16_t wfilter(filterList); + utf16_t wdir(dir); + wchar_t wfilename[PATH_MAX + 1] = L""; + + wchar_t *p = wfilter; + while(*p != L'\0') { + if(*p == L'\t') *p = L'\0'; + p++; + } + + if(path.empty() == false) { + //clear COMDLG32 MRU (most recently used) file list + //this is required in order for lpstrInitialDir to be honored in Windows 7 and above + registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/LastVisitedPidlMRU/"); + registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/OpenSavePidlMRU/"); + } + + OPENFILENAME ofn; + memset(&ofn, 0, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = &parent != &Window::none() ? parent.p.hwnd : 0; + ofn.lpstrFilter = wfilter; + ofn.lpstrInitialDir = wdir; + ofn.lpstrFile = wfilename; + ofn.nMaxFile = PATH_MAX; + ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrDefExt = L""; + + bool result = (save == false ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn)); + if(result == false) return ""; + string name = (const char*)utf8_t(wfilename); + name.transform("\\", "/"); + return name; +} + +string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) { + return FileDialog(false, parent, path, filter); +} + +string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) { + return FileDialog(true, parent, path, filter); +} + +string pDialogWindow::folderSelect(Window &parent, const string &path) { + wchar_t wfilename[PATH_MAX + 1] = L""; + BROWSEINFO bi; + bi.hwndOwner = &parent != &Window::none() ? parent.p.hwnd : 0; + bi.pidlRoot = NULL; + bi.pszDisplayName = wfilename; + bi.lpszTitle = L""; + 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, wfilename)) { + result = true; + IMalloc *imalloc = 0; + if(SUCCEEDED(SHGetMalloc(&imalloc))) { + imalloc->Free(pidl); + imalloc->Release(); + } + } + } + if(result == false) return ""; + string name = (const char*)utf8_t(wfilename); + if(name == "") return ""; + name.transform("\\", "/"); + if(name.endswith("/") == false) name.append("/"); + return name; +} \ No newline at end of file diff --git a/kaijuu/phoenix/windows/font.cpp b/kaijuu/phoenix/windows/font.cpp new file mode 100644 index 00000000..de42f24d --- /dev/null +++ b/kaijuu/phoenix/windows/font.cpp @@ -0,0 +1,44 @@ +Geometry pFont::geometry(const string &description, const string &text) { + HFONT hfont = pFont::create(description); + Geometry geometry = pFont::geometry(hfont, text); + pFont::free(hfont); + return geometry; +} + +HFONT pFont::create(const string &description) { + lstring part; + part.split(",", description); + for(auto &item : part) item.trim(" "); + + string family = "Sans"; + unsigned size = 8u; + bool bold = false; + bool italic = false; + + if(part[0] != "") family = part[0]; + if(part.size() >= 2) size = decimal(part[1]); + if(part.size() >= 3) bold = part[2].position("Bold"); + if(part.size() >= 3) italic = part[2].position("Italic"); + + return CreateFont( + -(size * 96.0 / 72.0 + 0.5), + 0, 0, 0, bold == false ? FW_NORMAL : FW_BOLD, italic, 0, 0, 0, 0, 0, 0, 0, + utf16_t(family) + ); +} + +void pFont::free(HFONT hfont) { + DeleteObject(hfont); +} + +Geometry pFont::geometry(HFONT hfont, const string &text_) { + //temporary fix: empty text string returns height of zero; bad for eg Button height + string text = (text_ == "" ? " " : text_); + + HDC hdc = GetDC(0); + SelectObject(hdc, hfont); + RECT rc = { 0, 0, 0, 0 }; + DrawText(hdc, utf16_t(text), -1, &rc, DT_CALCRECT); + ReleaseDC(0, hdc); + return { 0, 0, rc.right, rc.bottom }; +} diff --git a/kaijuu/phoenix/windows/keyboard.cpp b/kaijuu/phoenix/windows/keyboard.cpp new file mode 100644 index 00000000..1edffcb3 --- /dev/null +++ b/kaijuu/phoenix/windows/keyboard.cpp @@ -0,0 +1,137 @@ +void pKeyboard::initialize() { + auto append = [](Keyboard::Scancode scancode, unsigned keysym) { + settings->keymap.insert(scancode, keysym); + }; + + append(Keyboard::Scancode::Escape, VK_ESCAPE); + append(Keyboard::Scancode::F1, VK_F1); + append(Keyboard::Scancode::F2, VK_F2); + append(Keyboard::Scancode::F3, VK_F3); + append(Keyboard::Scancode::F4, VK_F4); + append(Keyboard::Scancode::F5, VK_F5); + append(Keyboard::Scancode::F6, VK_F6); + append(Keyboard::Scancode::F7, VK_F7); + append(Keyboard::Scancode::F8, VK_F8); + append(Keyboard::Scancode::F9, VK_F9); + append(Keyboard::Scancode::F10, VK_F10); + append(Keyboard::Scancode::F11, VK_F11); + append(Keyboard::Scancode::F12, VK_F12); + + append(Keyboard::Scancode::PrintScreen, VK_SNAPSHOT); + append(Keyboard::Scancode::ScrollLock, VK_SCROLL); + append(Keyboard::Scancode::Pause, VK_PAUSE); + + append(Keyboard::Scancode::Insert, VK_INSERT); + append(Keyboard::Scancode::Delete, VK_DELETE); + append(Keyboard::Scancode::Home, VK_HOME); + append(Keyboard::Scancode::End, VK_END); + append(Keyboard::Scancode::PageUp, VK_PRIOR); + append(Keyboard::Scancode::PageDown, VK_NEXT); + + append(Keyboard::Scancode::Up, VK_UP); + append(Keyboard::Scancode::Down, VK_DOWN); + append(Keyboard::Scancode::Left, VK_LEFT); + append(Keyboard::Scancode::Right, VK_RIGHT); + + append(Keyboard::Scancode::Grave, VK_OEM_3); + append(Keyboard::Scancode::Number1, '1'); + append(Keyboard::Scancode::Number2, '2'); + append(Keyboard::Scancode::Number3, '3'); + append(Keyboard::Scancode::Number4, '4'); + append(Keyboard::Scancode::Number5, '5'); + append(Keyboard::Scancode::Number6, '6'); + append(Keyboard::Scancode::Number7, '7'); + append(Keyboard::Scancode::Number8, '8'); + append(Keyboard::Scancode::Number9, '9'); + append(Keyboard::Scancode::Number0, '0'); + append(Keyboard::Scancode::Minus, VK_OEM_MINUS); + append(Keyboard::Scancode::Equal, VK_OEM_PLUS); + append(Keyboard::Scancode::Backspace, VK_BACK); + + append(Keyboard::Scancode::BracketLeft, VK_OEM_4); + append(Keyboard::Scancode::BracketRight, VK_OEM_6); + append(Keyboard::Scancode::Backslash, VK_OEM_5); + append(Keyboard::Scancode::Semicolon, VK_OEM_1); + append(Keyboard::Scancode::Apostrophe, VK_OEM_7); + append(Keyboard::Scancode::Comma, VK_OEM_COMMA); + append(Keyboard::Scancode::Period, VK_OEM_PERIOD); + append(Keyboard::Scancode::Slash, VK_OEM_2); + + append(Keyboard::Scancode::Tab, VK_TAB); + append(Keyboard::Scancode::CapsLock, VK_CAPITAL); + append(Keyboard::Scancode::Return, VK_RETURN); + append(Keyboard::Scancode::ShiftLeft, VK_LSHIFT); + append(Keyboard::Scancode::ShiftRight, VK_RSHIFT); + append(Keyboard::Scancode::ControlLeft, VK_LCONTROL); + append(Keyboard::Scancode::ControlRight, VK_RCONTROL); + append(Keyboard::Scancode::SuperLeft, VK_LWIN); + append(Keyboard::Scancode::SuperRight, VK_RWIN); + append(Keyboard::Scancode::AltLeft, VK_LMENU); + append(Keyboard::Scancode::AltRight, VK_RMENU); + append(Keyboard::Scancode::Space, VK_SPACE); + append(Keyboard::Scancode::Menu, VK_APPS); + + append(Keyboard::Scancode::A, 'A'); + append(Keyboard::Scancode::B, 'B'); + append(Keyboard::Scancode::C, 'C'); + append(Keyboard::Scancode::D, 'D'); + append(Keyboard::Scancode::E, 'E'); + append(Keyboard::Scancode::F, 'F'); + append(Keyboard::Scancode::G, 'G'); + append(Keyboard::Scancode::H, 'H'); + append(Keyboard::Scancode::I, 'I'); + append(Keyboard::Scancode::J, 'J'); + append(Keyboard::Scancode::K, 'K'); + append(Keyboard::Scancode::L, 'L'); + append(Keyboard::Scancode::M, 'M'); + append(Keyboard::Scancode::N, 'N'); + append(Keyboard::Scancode::O, 'O'); + append(Keyboard::Scancode::P, 'P'); + append(Keyboard::Scancode::Q, 'Q'); + append(Keyboard::Scancode::R, 'R'); + append(Keyboard::Scancode::S, 'S'); + append(Keyboard::Scancode::T, 'T'); + append(Keyboard::Scancode::U, 'U'); + append(Keyboard::Scancode::V, 'V'); + append(Keyboard::Scancode::W, 'W'); + append(Keyboard::Scancode::X, 'X'); + append(Keyboard::Scancode::Y, 'Y'); + append(Keyboard::Scancode::Z, 'Z'); + + append(Keyboard::Scancode::NumLock, VK_NUMLOCK); + append(Keyboard::Scancode::Divide, VK_DIVIDE); + append(Keyboard::Scancode::Multiply, VK_MULTIPLY); + append(Keyboard::Scancode::Subtract, VK_SUBTRACT); + append(Keyboard::Scancode::Add, VK_ADD); +//append(Keyboard::Scancode::Enter, ...); + append(Keyboard::Scancode::Point, VK_DECIMAL); + + append(Keyboard::Scancode::Keypad1, VK_NUMPAD1); + append(Keyboard::Scancode::Keypad2, VK_NUMPAD2); + append(Keyboard::Scancode::Keypad3, VK_NUMPAD3); + append(Keyboard::Scancode::Keypad4, VK_NUMPAD4); + append(Keyboard::Scancode::Keypad5, VK_NUMPAD5); + append(Keyboard::Scancode::Keypad6, VK_NUMPAD6); + append(Keyboard::Scancode::Keypad7, VK_NUMPAD7); + append(Keyboard::Scancode::Keypad8, VK_NUMPAD8); + append(Keyboard::Scancode::Keypad9, VK_NUMPAD9); + append(Keyboard::Scancode::Keypad0, VK_NUMPAD0); +} + +bool pKeyboard::pressed(Keyboard::Scancode scancode) { + return GetAsyncKeyState(settings->keymap.lhs[scancode]) & 0x8000; +} + +vector pKeyboard::state() { + vector output; + output.resize((unsigned)Keyboard::Scancode::Limit); + for(auto &n : output) n = false; + + for(auto &n : settings->keymap.rhs) { + if(GetAsyncKeyState(n.name) & 0x8000) { + output[(unsigned)n.data] = true; + } + } + + return output; +} diff --git a/kaijuu/phoenix/windows/message-window.cpp b/kaijuu/phoenix/windows/message-window.cpp new file mode 100644 index 00000000..fca126f4 --- /dev/null +++ b/kaijuu/phoenix/windows/message-window.cpp @@ -0,0 +1,41 @@ +static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, UINT response) { + if(response == IDOK) return MessageWindow::Response::Ok; + if(response == IDCANCEL) return MessageWindow::Response::Cancel; + if(response == IDYES) return MessageWindow::Response::Yes; + if(response == IDNO) return MessageWindow::Response::No; + if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel; + if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { + UINT flags = MB_ICONINFORMATION; + if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; + if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; + if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; + return MessageWindow_response(buttons, MessageBox(&parent != &Window::none() ? parent.p.hwnd : 0, utf16_t(text), L"", flags)); +} + +MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { + UINT flags = MB_ICONQUESTION; + if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; + if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; + if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; + return MessageWindow_response(buttons, MessageBox(&parent != &Window::none() ? parent.p.hwnd : 0, utf16_t(text), L"", flags)); +} + +MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { + UINT flags = MB_ICONWARNING; + if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; + if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; + if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; + return MessageWindow_response(buttons, MessageBox(&parent != &Window::none() ? parent.p.hwnd : 0, utf16_t(text), L"", flags)); +} + +MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { + UINT flags = MB_ICONERROR; + if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; + if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; + if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; + return MessageWindow_response(buttons, MessageBox(&parent != &Window::none() ? parent.p.hwnd : 0, utf16_t(text), L"", flags)); +} diff --git a/kaijuu/phoenix/windows/mouse.cpp b/kaijuu/phoenix/windows/mouse.cpp new file mode 100644 index 00000000..e5004645 --- /dev/null +++ b/kaijuu/phoenix/windows/mouse.cpp @@ -0,0 +1,14 @@ +Position pMouse::position() { + POINT point = { 0 }; + GetCursorPos(&point); + return { point.x, point.y }; +} + +bool pMouse::pressed(Mouse::Button button) { + switch(button) { + case Mouse::Button::Left: return GetAsyncKeyState(VK_LBUTTON) & 0x8000; + case Mouse::Button::Middle: return GetAsyncKeyState(VK_MBUTTON) & 0x8000; + case Mouse::Button::Right: return GetAsyncKeyState(VK_RBUTTON) & 0x8000; + } + return false; +} \ No newline at end of file diff --git a/kaijuu/phoenix/windows/object.cpp b/kaijuu/phoenix/windows/object.cpp new file mode 100644 index 00000000..78811d79 --- /dev/null +++ b/kaijuu/phoenix/windows/object.cpp @@ -0,0 +1,13 @@ +vector pObject::objects; + +pObject::pObject(Object &object) : object(object) { + static unsigned uniqueId = 100; + objects.append(this); + id = uniqueId++; + locked = false; +} + +pObject* pObject::find(unsigned id) { + for(auto &item : objects) if(item->id == id) return item; + return 0; +} diff --git a/kaijuu/phoenix/windows/phoenix.Manifest b/kaijuu/phoenix/windows/phoenix.Manifest new file mode 100644 index 00000000..45fbb4cd --- /dev/null +++ b/kaijuu/phoenix/windows/phoenix.Manifest @@ -0,0 +1,14 @@ + + + + + + + + + + + true + + + diff --git a/kaijuu/phoenix/windows/phoenix.rc b/kaijuu/phoenix/windows/phoenix.rc new file mode 100644 index 00000000..89fb8dc2 --- /dev/null +++ b/kaijuu/phoenix/windows/phoenix.rc @@ -0,0 +1 @@ +1 24 "phoenix.Manifest" diff --git a/kaijuu/phoenix/windows/platform.cpp b/kaijuu/phoenix/windows/platform.cpp new file mode 100644 index 00000000..1214f2c2 --- /dev/null +++ b/kaijuu/phoenix/windows/platform.cpp @@ -0,0 +1,479 @@ +#include "platform.hpp" +#include "utility.cpp" +#include "settings.cpp" + +#include "desktop.cpp" +#include "keyboard.cpp" +#include "mouse.cpp" +#include "dialog-window.cpp" +#include "message-window.cpp" + +#include "object.cpp" +#include "font.cpp" +#include "timer.cpp" +#include "window.cpp" + +#include "action/action.cpp" +#include "action/menu.cpp" +#include "action/separator.cpp" +#include "action/item.cpp" +#include "action/check-item.cpp" +#include "action/radio-item.cpp" + +#include "widget/widget.cpp" +#include "widget/button.cpp" +#include "widget/canvas.cpp" +#include "widget/check-box.cpp" +#include "widget/combo-box.cpp" +#include "widget/hex-edit.cpp" +#include "widget/horizontal-scroll-bar.cpp" +#include "widget/horizontal-slider.cpp" +#include "widget/label.cpp" +#include "widget/line-edit.cpp" +#include "widget/list-view.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-box.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +static bool OS_keyboardProc(HWND, UINT, WPARAM, LPARAM); +static void OS_processDialogMessage(MSG&); +static LRESULT CALLBACK OS_windowProc(HWND, UINT, WPARAM, LPARAM); + +void pOS::main() { + MSG msg; + while(GetMessage(&msg, 0, 0, 0)) { + OS_processDialogMessage(msg); + } +} + +bool pOS::pendingEvents() { + MSG msg; + return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); +} + +void pOS::processEvents() { + while(pendingEvents()) { + MSG msg; + if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { + OS_processDialogMessage(msg); + } + } +} + +void OS_processDialogMessage(MSG &msg) { + if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP + || msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP) { + if(OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam)) { + DispatchMessage(&msg); + return; + } + } + + if(!IsDialogMessage(GetForegroundWindow(), &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void pOS::quit() { + osQuit = true; + PostQuitMessage(0); +} + +void pOS::initialize() { + CoInitialize(0); + InitCommonControls(); + + WNDCLASS wc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2)); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = OS_windowProc; + wc.lpszClassName = L"phoenix_window"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Canvas_windowProc; + wc.lpszClassName = L"phoenix_canvas"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Label_windowProc; + wc.lpszClassName = L"phoenix_label"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Viewport_windowProc; + wc.lpszClassName = L"phoenix_viewport"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + settings = new Settings; + pKeyboard::initialize(); +} + +static bool OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + if(msg != WM_KEYDOWN && msg != WM_SYSKEYDOWN && msg != WM_KEYUP && msg != WM_SYSKEYUP) return false; + + GUITHREADINFO info; + memset(&info, 0, sizeof(GUITHREADINFO)); + info.cbSize = sizeof(GUITHREADINFO); + GetGUIThreadInfo(GetCurrentThreadId(), &info); + Object *object = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA); + if(object == nullptr) return false; + + if(dynamic_cast(object)) { + Window &window = (Window&)*object; + if(pWindow::modal.size() > 0 && !pWindow::modal.find(&window.p)) return false; + Keyboard::Keycode keysym = Keysym(wparam, lparam); + if(keysym != Keyboard::Keycode::None) { + if((msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) && window.onKeyPress) window.onKeyPress(keysym); + if((msg == WM_KEYUP || msg == WM_SYSKEYUP) && window.onKeyRelease) window.onKeyRelease(keysym); + } + return false; + } + + if(msg == WM_KEYDOWN) { + if(dynamic_cast(object)) { + ListView &listView = (ListView&)*object; + if(wparam == VK_RETURN) { + if(listView.onActivate) listView.onActivate(); + } + } else if(dynamic_cast(object)) { + LineEdit &lineEdit = (LineEdit&)*object; + if(wparam == VK_RETURN) { + if(lineEdit.onActivate) lineEdit.onActivate(); + } + } else if(dynamic_cast(object)) { + TextEdit &textEdit = (TextEdit&)*object; + if(wparam == 'A' && GetKeyState(VK_CONTROL) < 0) { + //Ctrl+A = select all text + //note: this is not a standard accelerator on Windows + Edit_SetSel(textEdit.p.hwnd, 0, ~0); + return true; + } else if(wparam == 'V' && GetKeyState(VK_CONTROL) < 0) { + //Ctrl+V = paste text + //note: this formats Unix (LF) and OS9 (CR) line-endings to Windows (CR+LF) line-endings + //this is necessary as the EDIT control only supports Windows line-endings + OpenClipboard(hwnd); + HANDLE handle = GetClipboardData(CF_UNICODETEXT); + if(handle) { + wchar_t *text = (wchar_t*)GlobalLock(handle); + if(text) { + string data = (const char*)utf8_t(text); + data.replace("\r\n", "\n"); + data.replace("\r", "\n"); + data.replace("\n", "\r\n"); + GlobalUnlock(handle); + utf16_t output(data); + HGLOBAL resource = GlobalAlloc(GMEM_MOVEABLE, (wcslen(output) + 1) * sizeof(wchar_t)); + if(resource) { + wchar_t *write = (wchar_t*)GlobalLock(resource); + if(write) { + wcscpy(write, output); + GlobalUnlock(write); + if(SetClipboardData(CF_UNICODETEXT, resource) == FALSE) { + GlobalFree(resource); + } + } + } + } + } + CloseClipboard(); + return false; + } + } + } + + return false; +} + +static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + Object *object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(!object || !dynamic_cast(object)) return DefWindowProc(hwnd, msg, wparam, lparam); + Window &window = (Window&)*object; + + bool process = true; + if(pWindow::modal.size() > 0 && !pWindow::modal.find(&window.p)) process = false; + if(osQuit) process = false; + + if(process) switch(msg) { + case WM_CLOSE: { + window.state.ignore = false; + if(window.onClose) window.onClose(); + if(window.state.ignore == false) { + window.setVisible(false); + window.setModal(false); + } + return TRUE; + } + + case WM_MOVE: { + if(window.p.locked) break; + + Geometry geometry = window.geometry(); + window.state.geometry.x = geometry.x; + window.state.geometry.y = geometry.y; + + if(window.onMove) window.onMove(); + break; + } + + case WM_SIZE: { + if(window.p.locked) break; + SetWindowPos(window.p.hstatus, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED); + + Geometry geometry = window.geometry(); + window.state.geometry.width = geometry.width; + window.state.geometry.height = geometry.height; + + for(auto &layout : window.state.layout) { + Geometry geom = window.geometry(); + geom.x = geom.y = 0; + layout.setGeometry(geom); + } + + if(window.onSize) window.onSize(); + break; + } + + case WM_GETMINMAXINFO: { + MINMAXINFO *mmi = (MINMAXINFO*)lparam; + //mmi->ptMinTrackSize.x = 256 + window.p.frameMargin().width; + //mmi->ptMinTrackSize.y = 256 + window.p.frameMargin().height; + //return TRUE; + break; + } + + case WM_ERASEBKGND: { + if(window.p.brush == 0) break; + RECT rc; + GetClientRect(window.p.hwnd, &rc); + PAINTSTRUCT ps; + BeginPaint(window.p.hwnd, &ps); + FillRect(ps.hdc, &rc, window.p.brush); + EndPaint(window.p.hwnd, &ps); + return TRUE; + } + + case WM_CTLCOLORBTN: + case WM_CTLCOLORSTATIC: { + Object *object = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA); + if(object && window.p.brush) { + HDC hdc = (HDC)wparam; + SetBkColor((HDC)wparam, window.p.brushColor); + return (INT_PTR)window.p.brush; + } + break; + } + + case WM_COMMAND: { + unsigned id = LOWORD(wparam); + HWND control = GetDlgItem(window.p.hwnd, id); + if(control == 0) { + pObject *object = (pObject*)pObject::find(id); + if(!object) break; + if(dynamic_cast(object)) { + Item &item = ((pItem*)object)->item; + if(item.onActivate) item.onActivate(); + } else if(dynamic_cast(object)) { + CheckItem &checkItem = ((pCheckItem*)object)->checkItem; + checkItem.setChecked(!checkItem.state.checked); + if(checkItem.onToggle) checkItem.onToggle(); + } else if(dynamic_cast(object)) { + RadioItem &radioItem = ((pRadioItem*)object)->radioItem; + if(radioItem.state.checked == false) { + radioItem.setChecked(); + if(radioItem.onActivate) radioItem.onActivate(); + } + } + } else { + Object *object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA); + if(!object) break; + if(dynamic_cast(object)) { + Button &button = (Button&)*object; + if(button.onActivate) button.onActivate(); + } else if(dynamic_cast(object)) { + CheckBox &checkBox = (CheckBox&)*object; + checkBox.setChecked(!checkBox.state.checked); + if(checkBox.onToggle) checkBox.onToggle(); + } else if(dynamic_cast(object)) { + ComboBox &comboBox = (ComboBox&)*object; + if(HIWORD(wparam) == CBN_SELCHANGE) { + if(comboBox.state.selection != comboBox.selection()) { + comboBox.state.selection = comboBox.selection(); + if(comboBox.onChange) comboBox.onChange(); + } + } + } else if(dynamic_cast(object)) { + LineEdit &lineEdit = (LineEdit&)*object; + if(HIWORD(wparam) == EN_CHANGE) { + if(lineEdit.p.locked == false && lineEdit.onChange) lineEdit.onChange(); + } + } else if(dynamic_cast(object)) { + RadioBox &radioBox = (RadioBox&)*object; + if(radioBox.state.checked == false) { + radioBox.setChecked(); + if(radioBox.onActivate) radioBox.onActivate(); + } + } else if(dynamic_cast(object)) { + TextEdit &textEdit = (TextEdit&)*object; + if(HIWORD(wparam) == EN_CHANGE) { + if(textEdit.p.locked == false && textEdit.onChange) textEdit.onChange(); + } + } + } + break; + } + + case WM_NOTIFY: { + unsigned id = LOWORD(wparam); + HWND control = GetDlgItem(window.p.hwnd, id); + if(control == 0) break; + Object *object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA); + if(object == 0) break; + if(dynamic_cast(object)) { + ListView &listView = (ListView&)*object; + LPNMHDR nmhdr = (LPNMHDR)lparam; + LPNMLISTVIEW nmlistview = (LPNMLISTVIEW)lparam; + + if(nmhdr->code == LVN_ITEMCHANGED && (nmlistview->uChanged & LVIF_STATE)) { + unsigned imagemask = ((nmlistview->uNewState & LVIS_STATEIMAGEMASK) >> 12) - 1; + if(imagemask == 0 || imagemask == 1) { + if(listView.p.locked == false && listView.onToggle) listView.onToggle(nmlistview->iItem); + } else if((nmlistview->uOldState & LVIS_FOCUSED) && !(nmlistview->uNewState & LVIS_FOCUSED)) { + listView.p.lostFocus = true; + } else if(!(nmlistview->uOldState & LVIS_SELECTED) && (nmlistview->uNewState & LVIS_SELECTED)) { + listView.p.lostFocus = false; + listView.state.selected = true; + listView.state.selection = listView.selection(); + if(listView.p.locked == false && listView.onChange) listView.onChange(); + } else if(listView.p.lostFocus == false && listView.selected() == false) { + listView.p.lostFocus = false; + listView.state.selected = false; + listView.state.selection = 0; + if(listView.p.locked == false && listView.onChange) listView.onChange(); + } + } else if(nmhdr->code == LVN_ITEMACTIVATE) { + if(listView.onActivate) listView.onActivate(); + } else if(nmhdr->code == NM_CUSTOMDRAW) { + LPNMLVCUSTOMDRAW lvcd = (LPNMLVCUSTOMDRAW)nmhdr; + switch(lvcd->nmcd.dwDrawStage) { + case CDDS_PREPAINT: + return CDRF_NOTIFYITEMDRAW; + case CDDS_ITEMPREPAINT: + if(listView.state.headerText.size() >= 2) { + //draw alternating row colors of there are two or more columns + if(lvcd->nmcd.dwItemSpec % 2) lvcd->clrTextBk = GetSysColor(COLOR_WINDOW) ^ 0x070707; + } + return CDRF_DODEFAULT; + default: + return CDRF_DODEFAULT; + } + } + } + break; + } + + case WM_HSCROLL: + case WM_VSCROLL: { + Object *object = 0; + if(lparam) { + object = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA); + } else { + unsigned id = LOWORD(wparam); + HWND control = GetDlgItem(window.p.hwnd, id); + if(control == 0) break; + object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA); + } + if(object == 0) break; + + if(dynamic_cast(object) + || dynamic_cast(object)) { + SCROLLINFO info; + memset(&info, 0, sizeof(SCROLLINFO)); + info.cbSize = sizeof(SCROLLINFO); + info.fMask = SIF_ALL; + GetScrollInfo((HWND)lparam, SB_CTL, &info); + + switch(LOWORD(wparam)) { + case SB_LEFT: info.nPos = info.nMin; break; + case SB_RIGHT: info.nPos = info.nMax; break; + case SB_LINELEFT: info.nPos--; break; + case SB_LINERIGHT: info.nPos++; break; + case SB_PAGELEFT: info.nPos -= info.nMax >> 3; break; + case SB_PAGERIGHT: info.nPos += info.nMax >> 3; break; + case SB_THUMBTRACK: info.nPos = info.nTrackPos; break; + } + + info.fMask = SIF_POS; + SetScrollInfo((HWND)lparam, SB_CTL, &info, TRUE); + + //Windows may clamp position to scrollbar range + GetScrollInfo((HWND)lparam, SB_CTL, &info); + + if(dynamic_cast(object)) { + HorizontalScrollBar &horizontalScrollBar = (HorizontalScrollBar&)*object; + if(horizontalScrollBar.state.position != info.nPos) { + horizontalScrollBar.state.position = info.nPos; + if(horizontalScrollBar.onChange) horizontalScrollBar.onChange(); + } + } else { + VerticalScrollBar &verticalScrollBar = (VerticalScrollBar&)*object; + if(verticalScrollBar.state.position != info.nPos) { + verticalScrollBar.state.position = info.nPos; + if(verticalScrollBar.onChange) verticalScrollBar.onChange(); + } + } + + return TRUE; + } + + if(dynamic_cast(object)) { + HorizontalSlider &horizontalSlider = (HorizontalSlider&)*object; + if(horizontalSlider.state.position != horizontalSlider.position()) { + horizontalSlider.state.position = horizontalSlider.position(); + if(horizontalSlider.onChange) horizontalSlider.onChange(); + } + } else if(dynamic_cast(object)) { + VerticalSlider &verticalSlider = (VerticalSlider&)*object; + if(verticalSlider.state.position != verticalSlider.position()) { + verticalSlider.state.position = verticalSlider.position(); + if(verticalSlider.onChange) verticalSlider.onChange(); + } + } + + break; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} diff --git a/kaijuu/phoenix/windows/platform.hpp b/kaijuu/phoenix/windows/platform.hpp new file mode 100644 index 00000000..96811796 --- /dev/null +++ b/kaijuu/phoenix/windows/platform.hpp @@ -0,0 +1,481 @@ +struct Settings { + bidirectional_map keymap; +}; + +struct pFont; +struct pObject; +struct pWindow; +struct pMenu; +struct pLayout; +struct pWidget; + +static bool osQuit = false; + +struct pFont { + static Geometry geometry(const string &description, const string &text); + + static HFONT create(const string &description); + static void free(HFONT hfont); + static Geometry geometry(HFONT hfont, const string &text); +}; + +struct pDesktop { + static Size size(); + static Geometry workspace(); +}; + +struct pKeyboard { + static bool pressed(Keyboard::Scancode scancode); + static vector state(); + + static void initialize(); +}; + +struct pMouse { + static Position position(); + static bool pressed(Mouse::Button button); +}; + +struct pDialogWindow { + static string fileOpen(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); +}; + +struct pMessageWindow { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + +struct pObject { + static vector objects; + + Object &object; + uintptr_t id; + bool locked; + + pObject(Object &object); + static pObject* find(unsigned id); + virtual ~pObject() {} + + void constructor() {} + void destructor() {} +}; + +struct pOS : public pObject { + static void main(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + static void initialize(); +}; + +struct pTimer : public pObject { + Timer &timer; + UINT_PTR htimer; + + void setEnabled(bool enabled); + void setInterval(unsigned milliseconds); + + pTimer(Timer &timer) : pObject(timer), timer(timer) {} + void constructor(); +}; + +struct pWindow : public pObject { + static vector modal; + static void updateModality(); + + Window &window; + HWND hwnd; + HMENU hmenu; + HWND hstatus; + HFONT hstatusfont; + HBRUSH brush; + COLORREF brushColor; + + static Window& none(); + + void append(Layout &layout); + void append(Menu &menu); + void append(Widget &widget); + Color backgroundColor(); + bool focused(); + Geometry frameMargin(); + Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); + void setBackgroundColor(const Color &color); + void setFocused(); + void setFullScreen(bool fullScreen); + void setGeometry(const Geometry &geometry); + void setMenuFont(const string &font); + void setMenuVisible(bool visible); + void setModal(bool modal); + void setResizable(bool resizable); + void setStatusFont(const string &font); + void setStatusText(const string &text); + void setStatusVisible(bool visible); + void setTitle(const string &text); + void setVisible(bool visible); + void setWidgetFont(const string &font); + + pWindow(Window &window) : pObject(window), window(window) {} + void constructor(); + void destructor(); + void updateMenu(); +}; + +struct pAction : public pObject { + Action &action; + Menu *parentMenu; + Window *parentWindow; + + void setEnabled(bool enabled); + void setVisible(bool visible); + + pAction(Action &action) : pObject(action), action(action) {} + void constructor(); +}; + +struct pMenu : public pAction { + Menu &menu; + HMENU hmenu; + HBITMAP hbitmap; + + void append(Action &action); + void remove(Action &action); + void setImage(const image &image); + void setText(const string &text); + + pMenu(Menu &menu) : pAction(menu), menu(menu), hbitmap(0) {} + void constructor(); + void destructor(); + void createBitmap(); + void update(Window &parentWindow, Menu *parentMenu = 0); +}; + +struct pSeparator : public pAction { + Separator &separator; + + pSeparator(Separator &separator) : pAction(separator), separator(separator) {} + void constructor(); + void destructor(); +}; + +struct pItem : public pAction { + Item &item; + HBITMAP hbitmap; + + void setImage(const image &image); + void setText(const string &text); + + pItem(Item &item) : pAction(item), item(item), hbitmap(0) {} + void constructor(); + void destructor(); + void createBitmap(); +}; + +struct pCheckItem : public pAction { + CheckItem &checkItem; + + bool checked(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} + void constructor(); + void destructor(); +}; + +struct pRadioItem : public pAction { + RadioItem &radioItem; + + bool checked(); + void setChecked(); + void setGroup(const set &group); + void setText(const string &text); + + pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} + void constructor(); + void destructor(); +}; + +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} +}; + +struct pWidget : public pSizable { + Widget &widget; + Window *parentWindow; + HWND hwnd; + HFONT hfont; + + bool enabled(); + virtual Geometry minimumGeometry(); + void setEnabled(bool enabled); + void setFocused(); + void setFont(const string &font); + virtual void setGeometry(const Geometry &geometry); + void setVisible(bool visible); + + pWidget(Widget &widget) : pSizable(widget), widget(widget) { parentWindow = &Window::none(); } + void constructor(); + void destructor(); + virtual void orphan(); + void setDefaultFont(); + void synchronize(); +}; + +struct pButton : public pWidget { + Button &button; + HBITMAP hbitmap; + HIMAGELIST himagelist; + + Geometry minimumGeometry(); + void setImage(const image &image, Orientation orientation); + void setText(const string &text); + + pButton(Button &button) : pWidget(button), button(button), hbitmap(0), himagelist(0) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pCanvas : public pWidget { + Canvas &canvas; + uint32_t *data; + + void setSize(const Size &size); + void update(); + + pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} + void constructor(); + void destructor(); + void orphan(); + void paint(); +}; + +struct pCheckBox : public pWidget { + CheckBox &checkBox; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckBox(CheckBox &checkBox) : pWidget(checkBox), checkBox(checkBox) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pComboBox : public pWidget { + ComboBox &comboBox; + + void append(const string &text); + void modify(unsigned row, const string &text); + void remove(unsigned row); + Geometry minimumGeometry(); + void reset(); + unsigned selection(); + void setSelection(unsigned row); + + pComboBox(ComboBox &comboBox) : pWidget(comboBox), comboBox(comboBox) {} + void constructor(); + void destructor(); + void orphan(); + void setGeometry(const Geometry &geometry); +}; + +struct pHexEdit : public pWidget { + HexEdit &hexEdit; + LRESULT CALLBACK (*windowProc)(HWND, UINT, LPARAM, WPARAM); + + void setColumns(unsigned columns); + void setLength(unsigned length); + void setOffset(unsigned offset); + void setRows(unsigned rows); + void update(); + + pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} + void constructor(); + void destructor(); + void orphan(); + bool keyPress(unsigned key); +}; + +struct pHorizontalScrollBar : public pWidget { + HorizontalScrollBar &horizontalScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pHorizontalSlider : public pWidget { + HorizontalSlider &horizontalSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalSlider(HorizontalSlider &horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pLabel : public pWidget { + Label &label; + + Geometry minimumGeometry(); + void setText(const string &text); + + pLabel(Label &label) : pWidget(label), label(label) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pLineEdit : public pWidget { + LineEdit &lineEdit; + + Geometry minimumGeometry(); + void setEditable(bool editable); + void setText(const string &text); + string text(); + + pLineEdit(LineEdit &lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pListView : public pWidget { + ListView &listView; + HIMAGELIST imageList; + bool lostFocus; + + void append(const lstring &text); + void autoSizeColumns(); + bool checked(unsigned row); + void modify(unsigned row, const lstring &text); + void remove(unsigned row); + void reset(); + bool selected(); + unsigned selection(); + void setCheckable(bool checkable); + void setChecked(unsigned row, bool checked); + void setHeaderText(const lstring &text); + void setHeaderVisible(bool visible); + void setImage(unsigned row, unsigned column, const image &image); + void setSelected(bool selected); + void setSelection(unsigned row); + + pListView(ListView &listView) : pWidget(listView), listView(listView), imageList(nullptr) {} + void constructor(); + void destructor(); + void orphan(); + void setGeometry(const Geometry &geometry); + void setImageList(); +}; + +struct pProgressBar : public pWidget { + ProgressBar &progressBar; + + Geometry minimumGeometry(); + void setPosition(unsigned position); + + pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pRadioBox : public pWidget { + RadioBox &radioBox; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(); + void setGroup(const set &group); + void setText(const string &text); + + pRadioBox(RadioBox &radioBox) : pWidget(radioBox), radioBox(radioBox) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pTextEdit : public pWidget { + TextEdit &textEdit; + + void setCursorPosition(unsigned position); + void setEditable(bool editable); + void setText(const string &text); + void setWordWrap(bool wordWrap); + string text(); + + pTextEdit(TextEdit &textEdit) : pWidget(textEdit), textEdit(textEdit) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pVerticalScrollBar : public pWidget { + VerticalScrollBar &verticalScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pVerticalSlider : public pWidget { + VerticalSlider &verticalSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalSlider(VerticalSlider &verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pViewport : public pWidget { + Viewport &viewport; + + uintptr_t handle(); + + pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} + void constructor(); + void destructor(); + void orphan(); +}; diff --git a/kaijuu/phoenix/windows/settings.cpp b/kaijuu/phoenix/windows/settings.cpp new file mode 100644 index 00000000..343fc9fb --- /dev/null +++ b/kaijuu/phoenix/windows/settings.cpp @@ -0,0 +1 @@ +static Settings *settings = nullptr; \ No newline at end of file diff --git a/kaijuu/phoenix/windows/timer.cpp b/kaijuu/phoenix/windows/timer.cpp new file mode 100644 index 00000000..99fb5c00 --- /dev/null +++ b/kaijuu/phoenix/windows/timer.cpp @@ -0,0 +1,31 @@ +static vector timers; + +static void CALLBACK Timer_timeoutProc(HWND hwnd, UINT msg, UINT_PTR timerID, DWORD time) { + for(auto &timer : timers) { + if(timer->htimer == timerID) { + if(timer->timer.onTimeout) timer->timer.onTimeout(); + return; + } + } +} + +void pTimer::setEnabled(bool enabled) { + if(htimer) { + KillTimer(NULL, htimer); + htimer = 0; + } + + if(enabled == true) { + htimer = SetTimer(NULL, 0U, timer.state.milliseconds, Timer_timeoutProc); + } +} + +void pTimer::setInterval(unsigned milliseconds) { + //destroy and recreate timer if interval changed + setEnabled(timer.state.enabled); +} + +void pTimer::constructor() { + timers.append(this); + htimer = 0; +} diff --git a/kaijuu/phoenix/windows/utility.cpp b/kaijuu/phoenix/windows/utility.cpp new file mode 100644 index 00000000..c247d5cc --- /dev/null +++ b/kaijuu/phoenix/windows/utility.cpp @@ -0,0 +1,150 @@ +static const unsigned Windows2000 = 0x0500; +static const unsigned WindowsXP = 0x0501; +static const unsigned WindowsVista = 0x0600; +static const unsigned Windows7 = 0x0601; + +static unsigned OsVersion() { + OSVERSIONINFO versionInfo = { 0 }; + versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&versionInfo); + return (versionInfo.dwMajorVersion << 8) + (versionInfo.dwMajorVersion << 0); +} + +static HBITMAP CreateBitmap(const image &image) { + HDC hdc = GetDC(0); + BITMAPINFO bitmapInfo; + memset(&bitmapInfo, 0, sizeof(BITMAPINFO)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = image.width; + bitmapInfo.bmiHeader.biHeight = -image.height; //bitmaps are stored upside down unless we negate height + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = image.width * image.height * 4; + void *bits = nullptr; + HBITMAP hbitmap = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0); + if(bits) memcpy(bits, image.data, image.width * image.height * 4); + ReleaseDC(0, hdc); + return hbitmap; +} + +static Keyboard::Keycode Keysym(unsigned keysym, unsigned keyflags) { + #define pressed(keysym) (GetAsyncKeyState(keysym) & 0x8000) + #define enabled(keysym) (GetKeyState(keysym)) + #define shifted() (pressed(VK_LSHIFT) || pressed(VK_RSHIFT)) + #define extended() (keyflags & (1 << 24)) + + switch(keysym) { + case VK_ESCAPE: return Keyboard::Keycode::Escape; + case VK_F1: return Keyboard::Keycode::F1; + case VK_F2: return Keyboard::Keycode::F2; + case VK_F3: return Keyboard::Keycode::F3; + case VK_F4: return Keyboard::Keycode::F4; + case VK_F5: return Keyboard::Keycode::F5; + case VK_F6: return Keyboard::Keycode::F6; + case VK_F7: return Keyboard::Keycode::F7; + case VK_F8: return Keyboard::Keycode::F8; + case VK_F9: return Keyboard::Keycode::F9; + //Keyboard::Keycode::F10 (should be captured under VK_MENU from WM_SYSKEY(UP,DOWN); but this is not working...) + case VK_F11: return Keyboard::Keycode::F11; + case VK_F12: return Keyboard::Keycode::F12; + + //Keyboard::Keycode::PrintScreen + //Keyboard::Keycode::SysRq + case VK_SCROLL: return Keyboard::Keycode::ScrollLock; + case VK_PAUSE: return Keyboard::Keycode::Pause; + //Keyboard::Keycode::Break + + case VK_INSERT: return extended() ? Keyboard::Keycode::Insert : Keyboard::Keycode::KeypadInsert; + case VK_DELETE: return extended() ? Keyboard::Keycode::Delete : Keyboard::Keycode::KeypadDelete; + case VK_HOME: return extended() ? Keyboard::Keycode::Home : Keyboard::Keycode::KeypadHome; + case VK_END: return extended() ? Keyboard::Keycode::End : Keyboard::Keycode::KeypadEnd; + case VK_PRIOR: return extended() ? Keyboard::Keycode::PageUp : Keyboard::Keycode::KeypadPageUp; + case VK_NEXT: return extended() ? Keyboard::Keycode::PageDown : Keyboard::Keycode::KeypadPageDown; + + case VK_UP: return extended() ? Keyboard::Keycode::Up : Keyboard::Keycode::KeypadUp; + case VK_DOWN: return extended() ? Keyboard::Keycode::Down : Keyboard::Keycode::KeypadDown; + case VK_LEFT: return extended() ? Keyboard::Keycode::Left : Keyboard::Keycode::KeypadLeft; + case VK_RIGHT: return extended() ? Keyboard::Keycode::Right : Keyboard::Keycode::KeypadRight; + + case VK_OEM_3: return !shifted() ? Keyboard::Keycode::Grave : Keyboard::Keycode::Tilde; + case '1': return !shifted() ? Keyboard::Keycode::Number1 : Keyboard::Keycode::Exclamation; + case '2': return !shifted() ? Keyboard::Keycode::Number2 : Keyboard::Keycode::At; + case '3': return !shifted() ? Keyboard::Keycode::Number3 : Keyboard::Keycode::Pound; + case '4': return !shifted() ? Keyboard::Keycode::Number4 : Keyboard::Keycode::Dollar; + case '5': return !shifted() ? Keyboard::Keycode::Number5 : Keyboard::Keycode::Percent; + case '6': return !shifted() ? Keyboard::Keycode::Number6 : Keyboard::Keycode::Power; + case '7': return !shifted() ? Keyboard::Keycode::Number7 : Keyboard::Keycode::Ampersand; + case '8': return !shifted() ? Keyboard::Keycode::Number8 : Keyboard::Keycode::Asterisk; + case '9': return !shifted() ? Keyboard::Keycode::Number9 : Keyboard::Keycode::ParenthesisLeft; + case '0': return !shifted() ? Keyboard::Keycode::Number0 : Keyboard::Keycode::ParenthesisRight; + case VK_OEM_MINUS: return !shifted() ? Keyboard::Keycode::Minus : Keyboard::Keycode::Underscore; + case VK_OEM_PLUS: return !shifted() ? Keyboard::Keycode::Equal : Keyboard::Keycode::Plus; + case VK_BACK: return Keyboard::Keycode::Backspace; + + case VK_OEM_4: return !shifted() ? Keyboard::Keycode::BracketLeft : Keyboard::Keycode::BraceLeft; + case VK_OEM_6: return !shifted() ? Keyboard::Keycode::BracketRight : Keyboard::Keycode::BraceRight; + case VK_OEM_5: return !shifted() ? Keyboard::Keycode::Backslash : Keyboard::Keycode::Pipe; + case VK_OEM_1: return !shifted() ? Keyboard::Keycode::Semicolon : Keyboard::Keycode::Colon; + case VK_OEM_7: return !shifted() ? Keyboard::Keycode::Apostrophe : Keyboard::Keycode::Quote; + case VK_OEM_COMMA: return !shifted() ? Keyboard::Keycode::Comma : Keyboard::Keycode::CaretLeft; + case VK_OEM_PERIOD: return !shifted() ? Keyboard::Keycode::Period : Keyboard::Keycode::CaretRight; + case VK_OEM_2: return !shifted() ? Keyboard::Keycode::Slash : Keyboard::Keycode::Question; + + case VK_TAB: return Keyboard::Keycode::Tab; + case VK_CAPITAL: return Keyboard::Keycode::CapsLock; + case VK_RETURN: return !extended() ? Keyboard::Keycode::Return : Keyboard::Keycode::Enter; + case VK_SHIFT: return !pressed(VK_RSHIFT) ? Keyboard::Keycode::ShiftLeft : Keyboard::Keycode::ShiftRight; + case VK_CONTROL: return !pressed(VK_RCONTROL) ? Keyboard::Keycode::ControlLeft : Keyboard::Keycode::ControlRight; + case VK_LWIN: return Keyboard::Keycode::SuperLeft; + case VK_RWIN: return Keyboard::Keycode::SuperRight; + case VK_MENU: + if(keyflags & (1 << 24)) return Keyboard::Keycode::AltRight; + return Keyboard::Keycode::AltLeft; + case VK_SPACE: return Keyboard::Keycode::Space; + case VK_APPS: return Keyboard::Keycode::Menu; + + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': + case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': + if(enabled(VK_CAPITAL)) { + if(shifted()) { + return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::a + keysym - 'A'); + } else { + return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::A + keysym - 'A'); + } + } else { + if(shifted()) { + return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::A + keysym - 'A'); + } else { + return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::a + keysym - 'A'); + } + } + break; + + case VK_NUMLOCK: return Keyboard::Keycode::NumLock; + case VK_DIVIDE: return Keyboard::Keycode::Divide; + case VK_MULTIPLY: return Keyboard::Keycode::Multiply; + case VK_SUBTRACT: return Keyboard::Keycode::Subtract; + case VK_ADD: return Keyboard::Keycode::Add; + case VK_DECIMAL: return Keyboard::Keycode::Point; + case VK_NUMPAD1: return Keyboard::Keycode::Keypad1; + case VK_NUMPAD2: return Keyboard::Keycode::Keypad2; + case VK_NUMPAD3: return Keyboard::Keycode::Keypad3; + case VK_NUMPAD4: return Keyboard::Keycode::Keypad4; + case VK_NUMPAD5: return Keyboard::Keycode::Keypad5; + case VK_NUMPAD6: return Keyboard::Keycode::Keypad6; + case VK_NUMPAD7: return Keyboard::Keycode::Keypad7; + case VK_NUMPAD8: return Keyboard::Keycode::Keypad8; + case VK_NUMPAD9: return Keyboard::Keycode::Keypad9; + case VK_NUMPAD0: return Keyboard::Keycode::Keypad0; + + case VK_CLEAR: return Keyboard::Keycode::KeypadCenter; + } + + return Keyboard::Keycode::None; + + #undef pressed + #undef enabled + #undef shifted + #undef extended +} diff --git a/kaijuu/phoenix/windows/widget/button.cpp b/kaijuu/phoenix/windows/widget/button.cpp new file mode 100644 index 00000000..41e7e283 --- /dev/null +++ b/kaijuu/phoenix/windows/widget/button.cpp @@ -0,0 +1,90 @@ +#ifndef Button_SetImageList + //MinGW/32-bit has painfully outdated platform headers ... + typedef struct { + HIMAGELIST himl; + RECT margin; + UINT uAlign; + } BUTTON_IMAGELIST, *PBUTTON_IMAGELIST; + + #define BUTTON_IMAGELIST_ALIGN_LEFT 0 + #define BUTTON_IMAGELIST_ALIGN_RIGHT 1 + #define BUTTON_IMAGELIST_ALIGN_TOP 2 + #define BUTTON_IMAGELIST_ALIGN_BOTTOM 3 + #define BUTTON_IMAGELIST_ALIGN_CENTER 4 + + #define BCM_FIRST 0x1600 + #define BCM_SETIMAGELIST (BCM_FIRST+2) + #define Button_SetImageList(hwnd, pbuttonImagelist) (WINBOOL)SNDMSG((hwnd),BCM_SETIMAGELIST,0,(LPARAM)(pbuttonImagelist)) +#endif + +Geometry pButton::minimumGeometry() { + Geometry geometry = pFont::geometry(hfont, button.state.text); + + if(button.state.orientation == Orientation::Horizontal) { + geometry.width += button.state.image.width; + geometry.height = max(button.state.image.height, geometry.height); + } + + if(button.state.orientation == Orientation::Vertical) { + geometry.width = max(button.state.image.width, geometry.width); + geometry.height += button.state.image.height; + } + + return { 0, 0, geometry.width + 20, geometry.height + 10 }; +} + +void pButton::setImage(const image &image, Orientation orientation) { + nall::image nallImage = image; + nallImage.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + + if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } + if(himagelist) { ImageList_Destroy(himagelist); himagelist = 0; } + + if(OsVersion() >= WindowsVista) { + hbitmap = CreateBitmap(nallImage); + SendMessage(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbitmap); + switch(orientation) { + case Orientation::Horizontal: SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~BS_TOP); break; + case Orientation::Vertical: SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | BS_TOP); break; + } + } else { + //Windows XP and earlier cannot display bitmaps and text at the same time with BM_SETIMAGE + //Use BCM_SETIMAGELIST instead. It does not support alpha blending, so blend with button color + //The XP theme and above use a gradient fade background, so it won't be a perfect match there + nallImage.alphaBlend(GetSysColor(COLOR_BTNFACE)); + hbitmap = CreateBitmap(nallImage); + himagelist = ImageList_Create(nallImage.width, nallImage.height, ILC_COLOR32, 1, 0); + ImageList_Add(himagelist, hbitmap, NULL); + BUTTON_IMAGELIST list; + list.himl = himagelist; + switch(orientation) { + case Orientation::Horizontal: SetRect(&list.margin, 5, 0, 0, 0); list.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT; break; + case Orientation::Vertical: SetRect(&list.margin, 0, 5, 0, 0); list.uAlign = BUTTON_IMAGELIST_ALIGN_TOP; break; + } + Button_SetImageList(hwnd, &list); + } +} + +void pButton::setText(const string &text) { + SetWindowText(hwnd, utf16_t(text)); +} + +void pButton::constructor() { + hwnd = CreateWindow(L"BUTTON", L"", WS_CHILD | WS_TABSTOP, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&button); + setDefaultFont(); + setImage(button.state.image, button.state.orientation); + setText(button.state.text); + synchronize(); +} + +void pButton::destructor() { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } + if(himagelist) { ImageList_Destroy(himagelist); himagelist = 0; } + DestroyWindow(hwnd); +} + +void pButton::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/windows/widget/canvas.cpp b/kaijuu/phoenix/windows/widget/canvas.cpp new file mode 100644 index 00000000..f2be9e38 --- /dev/null +++ b/kaijuu/phoenix/windows/widget/canvas.cpp @@ -0,0 +1,92 @@ +static LRESULT CALLBACK Canvas_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + Object *object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(object == nullptr) return DefWindowProc(hwnd, msg, wparam, lparam); + if(!dynamic_cast(object)) return DefWindowProc(hwnd, msg, wparam, lparam); + Canvas &canvas = (Canvas&)*object; + + if(msg == WM_GETDLGCODE) { + return DLGC_STATIC | DLGC_WANTCHARS; + } + + if(msg == WM_PAINT) { + canvas.p.paint(); + return TRUE; + } + + if(msg == WM_MOUSEMOVE) { + TRACKMOUSEEVENT tracker = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, hwnd }; + TrackMouseEvent(&tracker); + if(canvas.onMouseMove) canvas.onMouseMove({ (int16_t)LOWORD(lparam), (int16_t)HIWORD(lparam) }); + } + + if(msg == WM_MOUSELEAVE) { + if(canvas.onMouseLeave) canvas.onMouseLeave(); + } + + if(msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) { + if(canvas.onMousePress) switch(msg) { + case WM_LBUTTONDOWN: canvas.onMousePress(Mouse::Button::Left); break; + case WM_MBUTTONDOWN: canvas.onMousePress(Mouse::Button::Middle); break; + case WM_RBUTTONDOWN: canvas.onMousePress(Mouse::Button::Right); break; + } + } + + if(msg == WM_LBUTTONUP || msg == WM_MBUTTONUP || msg == WM_RBUTTONUP) { + if(canvas.onMouseRelease) switch(msg) { + case WM_LBUTTONUP: canvas.onMouseRelease(Mouse::Button::Left); break; + case WM_MBUTTONUP: canvas.onMouseRelease(Mouse::Button::Middle); break; + case WM_RBUTTONUP: canvas.onMouseRelease(Mouse::Button::Right); break; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +void pCanvas::setSize(const Size &size) { + delete[] data; + data = new uint32_t[size.width * size.height]; +} + +void pCanvas::update() { + memcpy(data, canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); + InvalidateRect(hwnd, 0, false); +} + +void pCanvas::constructor() { + data = new uint32_t[canvas.state.width * canvas.state.height]; + memcpy(data, canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); + hwnd = CreateWindow(L"phoenix_canvas", L"", WS_CHILD, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&canvas); + synchronize(); +} + +void pCanvas::destructor() { + DestroyWindow(hwnd); + delete[] data; +} + +void pCanvas::orphan() { + destructor(); + constructor(); +} + +void pCanvas::paint() { + RECT rc; + GetClientRect(hwnd, &rc); + unsigned width = canvas.state.width, height = canvas.state.height; + + BITMAPINFO bmi; + memset(&bmi, 0, sizeof(BITMAPINFO)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; //GDI stores bitmaps upside now; negative height flips bitmap + bmi.bmiHeader.biSizeImage = sizeof(uint32_t) * width * height; + + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + SetDIBitsToDevice(ps.hdc, 0, 0, width, height, 0, 0, 0, height, (void*)data, &bmi, DIB_RGB_COLORS); + EndPaint(hwnd, &ps); +} diff --git a/kaijuu/phoenix/windows/widget/check-box.cpp b/kaijuu/phoenix/windows/widget/check-box.cpp new file mode 100644 index 00000000..8f0d2eb8 --- /dev/null +++ b/kaijuu/phoenix/windows/widget/check-box.cpp @@ -0,0 +1,39 @@ +bool pCheckBox::checked() { + return SendMessage(hwnd, BM_GETCHECK, 0, 0); +} + +Geometry pCheckBox::minimumGeometry() { + Geometry geometry = pFont::geometry(hfont, checkBox.state.text); + return { 0, 0, geometry.width + 20, geometry.height + 4 }; +} + +void pCheckBox::setChecked(bool checked) { + SendMessage(hwnd, BM_SETCHECK, (WPARAM)checked, 0); +} + +void pCheckBox::setText(const string &text) { + SetWindowText(hwnd, utf16_t(text)); +} + +void pCheckBox::constructor() { + hwnd = CreateWindow( + L"BUTTON", L"", + WS_CHILD | WS_TABSTOP | BS_CHECKBOX, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&checkBox); + setDefaultFont(); + if(checkBox.state.checked) setChecked(true); + setText(checkBox.state.text); + synchronize(); + +} + +void pCheckBox::destructor() { + DestroyWindow(hwnd); +} + +void pCheckBox::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/windows/widget/combo-box.cpp b/kaijuu/phoenix/windows/widget/combo-box.cpp new file mode 100644 index 00000000..bff1170d --- /dev/null +++ b/kaijuu/phoenix/windows/widget/combo-box.cpp @@ -0,0 +1,70 @@ +void pComboBox::append(const string &text) { + SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)(wchar_t*)utf16_t(text)); + if(SendMessage(hwnd, CB_GETCOUNT, 0, 0) == 1) setSelection(0); +} + +Geometry pComboBox::minimumGeometry() { + unsigned maximumWidth = 0; + for(auto &text : comboBox.state.text) maximumWidth = max(maximumWidth, pFont::geometry(hfont, text).width); + return { 0, 0, maximumWidth + 24, pFont::geometry(hfont, " ").height + 10 }; +} + +void pComboBox::modify(unsigned row, const string &text) { + locked = true; + unsigned position = selection(); + SendMessage(hwnd, CB_DELETESTRING, row, 0); + SendMessage(hwnd, CB_INSERTSTRING, row, (LPARAM)(wchar_t*)utf16_t(text)); + setSelection(position); + locked = false; +} + +void pComboBox::remove(unsigned row) { + locked = true; + unsigned position = selection(); + SendMessage(hwnd, CB_DELETESTRING, row, 0); + if(position == row) setSelection(0); + locked = false; +} + +void pComboBox::reset() { + SendMessage(hwnd, CB_RESETCONTENT, 0, 0); +} + +unsigned pComboBox::selection() { + return SendMessage(hwnd, CB_GETCURSEL, 0, 0); +} + +void pComboBox::setSelection(unsigned row) { + SendMessage(hwnd, CB_SETCURSEL, row, 0); +} + +void pComboBox::constructor() { + hwnd = CreateWindow( + L"COMBOBOX", L"", + WS_CHILD | WS_TABSTOP | CBS_DROPDOWNLIST | CBS_HASSTRINGS, + 0, 0, 0, 0, + parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&comboBox); + setDefaultFont(); + for(auto &text : comboBox.state.text) append(text); + setSelection(comboBox.state.selection); + synchronize(); +} + +void pComboBox::destructor() { + DestroyWindow(hwnd); +} + +void pComboBox::orphan() { + destructor(); + constructor(); +} + +void pComboBox::setGeometry(const Geometry &geometry) { + SetWindowPos(hwnd, NULL, geometry.x, geometry.y, geometry.width, 1, SWP_NOZORDER); + RECT rc; + GetWindowRect(hwnd, &rc); + unsigned adjustedHeight = geometry.height - ((rc.bottom - rc.top) - SendMessage(hwnd, CB_GETITEMHEIGHT, (WPARAM)-1, 0)); + SendMessage(hwnd, CB_SETITEMHEIGHT, (WPARAM)-1, adjustedHeight); +} diff --git a/kaijuu/phoenix/windows/widget/hex-edit.cpp b/kaijuu/phoenix/windows/widget/hex-edit.cpp new file mode 100644 index 00000000..789f4faf --- /dev/null +++ b/kaijuu/phoenix/windows/widget/hex-edit.cpp @@ -0,0 +1,136 @@ +static LRESULT CALLBACK HexEdit_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + HexEdit &hexEdit = *(HexEdit*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(msg == WM_CHAR) { + if(hexEdit.p.keyPress(wparam)) return 0; + } + return hexEdit.p.windowProc(hwnd, msg, wparam, lparam); +} + +void pHexEdit::setColumns(unsigned columns) { + update(); +} + +void pHexEdit::setLength(unsigned length) { + update(); +} + +void pHexEdit::setOffset(unsigned offset) { + update(); +} + +void pHexEdit::setRows(unsigned rows) { + update(); +} + +void pHexEdit::update() { + if(!hexEdit.onRead) { + SetWindowText(hwnd, L""); + return; + } + + unsigned cursorPosition = Edit_GetSel(hwnd); + + string output; + unsigned offset = hexEdit.state.offset; + for(unsigned row = 0; row < hexEdit.state.rows; row++) { + output.append(hex<8>(offset)); + output.append(" "); + + string hexdata; + string ansidata = " "; + for(unsigned column = 0; column < hexEdit.state.columns; column++) { + if(offset < hexEdit.state.length) { + uint8_t data = hexEdit.onRead(offset++); + hexdata.append(hex<2>(data)); + hexdata.append(" "); + char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 }; + ansidata.append(buffer); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(offset >= hexEdit.state.length) break; + if(row != hexEdit.state.rows - 1) output.append("\r\n"); + } + + SetWindowText(hwnd, utf16_t(output)); + Edit_SetSel(hwnd, LOWORD(cursorPosition), HIWORD(cursorPosition)); +} + +void pHexEdit::constructor() { + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, L"EDIT", L"", + WS_CHILD | WS_TABSTOP | ES_READONLY | ES_MULTILINE | ES_WANTRETURN, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&hexEdit); + setDefaultFont(); + update(); + + windowProc = (LRESULT CALLBACK (*)(HWND, UINT, LPARAM, WPARAM))GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)HexEdit_windowProc); + synchronize(); +} + +void pHexEdit::destructor() { + DestroyWindow(hwnd); +} + +void pHexEdit::orphan() { + destructor(); + constructor(); +} + +bool pHexEdit::keyPress(unsigned scancode) { + if(!hexEdit.onRead) return false; + + unsigned position = LOWORD(Edit_GetSel(hwnd)); + unsigned lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 2; + unsigned cursorY = position / lineWidth; + unsigned cursorX = position % lineWidth; + + //convert scancode to hex nibble + if(scancode >= '0' && scancode <= '9') scancode = scancode - '0'; + else if(scancode >= 'A' && scancode <= 'F') scancode = scancode - 'A' + 10; + else if(scancode >= 'a' && scancode <= 'f') scancode = scancode - 'a' + 10; + else return false; + + if(cursorX >= 10) { + //not on an offset + cursorX -= 10; + if((cursorX % 3) != 2) { + //not on a space + bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low + cursorX /= 3; + if(cursorX < hexEdit.state.columns) { + //not in ANSI region + unsigned offset = hexEdit.state.offset + (cursorY * hexEdit.state.columns + cursorX); + + if(offset >= hexEdit.state.length) return false; //do not edit past end of data + uint8_t data = hexEdit.onRead(offset); + + //write modified value + if(cursorNibble == 1) { + data = (data & 0xf0) | (scancode << 0); + } else { + data = (data & 0x0f) | (scancode << 4); + } + if(hexEdit.onWrite) hexEdit.onWrite(offset, data); + + //auto-advance cursor to next nibble or byte + position++; + if(cursorNibble && cursorX != hexEdit.state.columns - 1) position++; + Edit_SetSel(hwnd, position, position); + + //refresh output to reflect modified data + update(); + } + } + } + + return true; +} diff --git a/kaijuu/phoenix/windows/widget/horizontal-scroll-bar.cpp b/kaijuu/phoenix/windows/widget/horizontal-scroll-bar.cpp new file mode 100644 index 00000000..250ac247 --- /dev/null +++ b/kaijuu/phoenix/windows/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,38 @@ +Geometry pHorizontalScrollBar::minimumGeometry() { + return { 0, 0, 0, 18 }; +} + +unsigned pHorizontalScrollBar::position() { + return GetScrollPos(hwnd, SB_CTL); +} + +void pHorizontalScrollBar::setLength(unsigned length) { + length += (length == 0); + SetScrollRange(hwnd, SB_CTL, 0, length - 1, TRUE); + horizontalScrollBar.setPosition(0); +} + +void pHorizontalScrollBar::setPosition(unsigned position) { + SetScrollPos(hwnd, SB_CTL, position, TRUE); +} + +void pHorizontalScrollBar::constructor() { + hwnd = CreateWindow( + L"SCROLLBAR", L"", WS_CHILD | WS_TABSTOP | SBS_HORZ, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&horizontalScrollBar); + unsigned position = horizontalScrollBar.state.position; + setLength(horizontalScrollBar.state.length); + horizontalScrollBar.setPosition(position); + synchronize(); +} + +void pHorizontalScrollBar::destructor() { + DestroyWindow(hwnd); +} + +void pHorizontalScrollBar::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/windows/widget/horizontal-slider.cpp b/kaijuu/phoenix/windows/widget/horizontal-slider.cpp new file mode 100644 index 00000000..807086ae --- /dev/null +++ b/kaijuu/phoenix/windows/widget/horizontal-slider.cpp @@ -0,0 +1,39 @@ +Geometry pHorizontalSlider::minimumGeometry() { + return { 0, 0, 0, 25 }; +} + +unsigned pHorizontalSlider::position() { + return SendMessage(hwnd, TBM_GETPOS, 0, 0); +} + +void pHorizontalSlider::setLength(unsigned length) { + length += (length == 0); + SendMessage(hwnd, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1)); + SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3)); + horizontalSlider.setPosition(0); +} + +void pHorizontalSlider::setPosition(unsigned position) { + SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)position); +} + +void pHorizontalSlider::constructor() { + hwnd = CreateWindow( + TRACKBAR_CLASS, L"", WS_CHILD | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_HORZ, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&horizontalSlider); + unsigned position = horizontalSlider.state.position; + setLength(horizontalSlider.state.length); + horizontalSlider.setPosition(position); + synchronize(); +} + +void pHorizontalSlider::destructor() { + DestroyWindow(hwnd); +} + +void pHorizontalSlider::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/windows/widget/label.cpp b/kaijuu/phoenix/windows/widget/label.cpp new file mode 100644 index 00000000..56f0d433 --- /dev/null +++ b/kaijuu/phoenix/windows/widget/label.cpp @@ -0,0 +1,64 @@ +Geometry pLabel::minimumGeometry() { + Geometry geometry = pFont::geometry(hfont, label.state.text); + return { 0, 0, geometry.width, geometry.height }; +} + +void pLabel::setText(const string &text) { + SetWindowText(hwnd, utf16_t(text)); + InvalidateRect(hwnd, 0, false); +} + +void pLabel::constructor() { + hwnd = CreateWindow(L"phoenix_label", L"", WS_CHILD, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&label); + setDefaultFont(); + setText(label.state.text); + synchronize(); +} + +void pLabel::destructor() { + DestroyWindow(hwnd); +} + +void pLabel::orphan() { + destructor(); + constructor(); +} + +static LRESULT CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + Window *window = (Window*)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA); + Label *label = (Label*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(!window || !label) return DefWindowProc(hwnd, msg, wparam, lparam); + + if(msg == WM_GETDLGCODE) { + return DLGC_STATIC | DLGC_WANTCHARS; + } + + if(msg == WM_ERASEBKGND) { + //background is erased during WM_PAINT to prevent flickering + return TRUE; + } + + if(msg == WM_PAINT) { + PAINTSTRUCT ps; + RECT rc; + BeginPaint(hwnd, &ps); + GetClientRect(hwnd, &rc); + FillRect(ps.hdc, &rc, window->p.brush ? window->p.brush : GetSysColorBrush(COLOR_3DFACE)); + SetBkColor(ps.hdc, window->p.brush ? window->p.brushColor : GetSysColor(COLOR_3DFACE)); + SelectObject(ps.hdc, ((Widget*)label)->p.hfont); + unsigned length = GetWindowTextLength(hwnd); + wchar_t text[length + 1]; + GetWindowText(hwnd, text, length + 1); + text[length] = 0; + DrawText(ps.hdc, text, -1, &rc, DT_CALCRECT | DT_END_ELLIPSIS); + unsigned height = rc.bottom; + GetClientRect(hwnd, &rc); + rc.top = (rc.bottom - height) / 2; + rc.bottom = rc.top + height; + DrawText(ps.hdc, text, -1, &rc, DT_LEFT | DT_END_ELLIPSIS); + EndPaint(hwnd, &ps); + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} diff --git a/kaijuu/phoenix/windows/widget/line-edit.cpp b/kaijuu/phoenix/windows/widget/line-edit.cpp new file mode 100644 index 00000000..eb6a8fb7 --- /dev/null +++ b/kaijuu/phoenix/windows/widget/line-edit.cpp @@ -0,0 +1,45 @@ +Geometry pLineEdit::minimumGeometry() { + Geometry geometry = pFont::geometry(hfont, lineEdit.state.text); + return { 0, 0, geometry.width + 12, geometry.height + 10 }; +} + +void pLineEdit::setEditable(bool editable) { + SendMessage(hwnd, EM_SETREADONLY, editable == false, 0); +} + +void pLineEdit::setText(const string &text) { + locked = true; + SetWindowText(hwnd, utf16_t(text)); + locked = false; +} + +string pLineEdit::text() { + unsigned length = GetWindowTextLength(hwnd); + wchar_t text[length + 1]; + GetWindowText(hwnd, text, length + 1); + text[length] = 0; + return (const char*)utf8_t(text); +} + +void pLineEdit::constructor() { + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, L"EDIT", L"", + WS_CHILD | WS_TABSTOP | ES_AUTOHSCROLL | ES_AUTOVSCROLL, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&lineEdit); + setDefaultFont(); + setEditable(lineEdit.state.editable); + setText(lineEdit.state.text); + synchronize(); +} + +void pLineEdit::destructor() { + lineEdit.state.text = text(); + DestroyWindow(hwnd); +} + +void pLineEdit::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/windows/widget/list-view.cpp b/kaijuu/phoenix/windows/widget/list-view.cpp new file mode 100644 index 00000000..11ae023f --- /dev/null +++ b/kaijuu/phoenix/windows/widget/list-view.cpp @@ -0,0 +1,210 @@ +unsigned ListView_GetColumnCount(HWND hwnd) { + unsigned count = 0; + LVCOLUMN column; + column.mask = LVCF_WIDTH; + while(ListView_GetColumn(hwnd, count++, &column)); + return --count; +} + +void pListView::append(const lstring &list) { + wchar_t empty[] = L""; + unsigned row = ListView_GetItemCount(hwnd); + LVITEM item; + item.mask = LVIF_TEXT; + item.iItem = row; + item.iSubItem = 0; + item.pszText = empty; + locked = true; + ListView_InsertItem(hwnd, &item); + locked = false; + for(unsigned column = 0; column < list.size(); column++) { + utf16_t wtext(list(column, "")); + ListView_SetItemText(hwnd, row, column, wtext); + } +} + +void pListView::autoSizeColumns() { + unsigned columns = ListView_GetColumnCount(hwnd); + for(unsigned n = 0; n < columns; n++) { + ListView_SetColumnWidth(hwnd, n, LVSCW_AUTOSIZE_USEHEADER); + } +} + +bool pListView::checked(unsigned row) { + return ListView_GetCheckState(hwnd, row); +} + +void pListView::modify(unsigned row, const lstring &list) { + for(unsigned n = 0; n < list.size(); n++) { + utf16_t wtext(list(n, "")); + ListView_SetItemText(hwnd, row, n, wtext); + } +} + +void pListView::remove(unsigned row) { + ListView_DeleteItem(hwnd, row); + setImageList(); +} + +void pListView::reset() { + ListView_DeleteAllItems(hwnd); +} + +bool pListView::selected() { + unsigned count = ListView_GetItemCount(hwnd); + for(unsigned n = 0; n < count; n++) { + if(ListView_GetItemState(hwnd, n, LVIS_SELECTED)) return true; + } + return false; +} + +unsigned pListView::selection() { + unsigned count = ListView_GetItemCount(hwnd); + for(unsigned n = 0; n < count; n++) { + if(ListView_GetItemState(hwnd, n, LVIS_SELECTED)) return n; + } + return listView.state.selection; +} + +void pListView::setCheckable(bool checkable) { + ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES | (checkable ? LVS_EX_CHECKBOXES : 0)); +} + +void pListView::setChecked(unsigned row, bool checked) { + locked = true; + ListView_SetCheckState(hwnd, row, checked); + locked = false; +} + +void pListView::setHeaderText(const lstring &list) { + while(ListView_DeleteColumn(hwnd, 0)); + + lstring headers = list; + if(headers.size() == 0) headers.append(""); //must have at least one column + + for(unsigned n = 0; n < headers.size(); n++) { + LVCOLUMN column; + column.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM; + column.fmt = LVCFMT_LEFT; + column.iSubItem = n; + utf16_t headerText(headers[n]); + column.pszText = headerText; + ListView_InsertColumn(hwnd, n, &column); + } + autoSizeColumns(); +} + +void pListView::setHeaderVisible(bool visible) { + SetWindowLong( + hwnd, GWL_STYLE, + (GetWindowLong(hwnd, GWL_STYLE) & ~LVS_NOCOLUMNHEADER) | + (visible ? 0 : LVS_NOCOLUMNHEADER) + ); +} + +void pListView::setImage(unsigned row, unsigned column, const image &image) { + setImageList(); +} + +void pListView::setSelected(bool selected) { + locked = true; + lostFocus = false; + if(selected == false) { + ListView_SetItemState(hwnd, -1, 0, LVIS_FOCUSED | LVIS_SELECTED); + } else { + setSelection(listView.state.selection); + } + locked = false; +} + +void pListView::setSelection(unsigned row) { + locked = true; + lostFocus = false; + ListView_SetItemState(hwnd, row, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); + locked = false; +} + +void pListView::constructor() { + lostFocus = false; + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, WC_LISTVIEW, L"", + WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | LVS_NOCOLUMNHEADER, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&listView); + setDefaultFont(); + setHeaderText(listView.state.headerText); + setHeaderVisible(listView.state.headerVisible); + setCheckable(listView.state.checkable); + for(auto &text : listView.state.text) append(text); + for(unsigned n = 0; n < listView.state.checked.size(); n++) setChecked(n, listView.state.checked[n]); + setImageList(); + if(listView.state.selected) setSelection(listView.state.selection); + autoSizeColumns(); + synchronize(); +} + +void pListView::destructor() { + DestroyWindow(hwnd); +} + +void pListView::orphan() { + destructor(); + constructor(); +} + +void pListView::setGeometry(const Geometry &geometry) { + pWidget::setGeometry(geometry); + autoSizeColumns(); +} + +void pListView::setImageList() { + auto &list = listView.state.image; + + if(imageList) { + ImageList_Destroy(imageList); + imageList = nullptr; + } + + bool found = false; + for(auto &row : listView.state.image) { + for(auto &column : row) { + if(column.empty() == false) { + found = true; + break; + } + } + } + if(found == false) return; + + imageList = ImageList_Create(15, 15, ILC_COLOR32, 1, 0); + nall::image image; + image.allocate(15, 15); + image.clear(GetSysColor(COLOR_WINDOW)); + ImageList_Add(imageList, CreateBitmap(image), NULL); + + for(unsigned row = 0; row < list.size(); row++) { + for(unsigned column = 0; column < list(row).size(); column++) { + nall::image image = list(row)(column); + if(image.empty()) continue; + image.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + image.scale(15, 15, Interpolation::Linear); + ImageList_Add(imageList, CreateBitmap(image), NULL); + } + } + + ListView_SetImageList(hwnd, imageList, LVSIL_SMALL); + + unsigned ID = 1; + for(unsigned row = 0; row < list.size(); row++) { + for(unsigned column = 0; column < list(row).size(); column++) { + if(list(row)(column).empty()) continue; //I_IMAGENONE does not work properly + LVITEM item; + item.mask = LVIF_IMAGE; + item.iItem = row; + item.iSubItem = column; + item.iImage = ID++; + ListView_SetItem(hwnd, &item); + } + } +} diff --git a/kaijuu/phoenix/windows/widget/progress-bar.cpp b/kaijuu/phoenix/windows/widget/progress-bar.cpp new file mode 100644 index 00000000..f4703f1e --- /dev/null +++ b/kaijuu/phoenix/windows/widget/progress-bar.cpp @@ -0,0 +1,25 @@ +Geometry pProgressBar::minimumGeometry() { + return { 0, 0, 0, 23 }; +} + +void pProgressBar::setPosition(unsigned position) { + SendMessage(hwnd, PBM_SETPOS, (WPARAM)position, 0); +} + +void pProgressBar::constructor() { + hwnd = CreateWindow(PROGRESS_CLASS, L"", WS_CHILD | PBS_SMOOTH, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&progressBar); + SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + SendMessage(hwnd, PBM_SETSTEP, MAKEWPARAM(1, 0), 0); + setPosition(progressBar.state.position); + synchronize(); +} + +void pProgressBar::destructor() { + DestroyWindow(hwnd); +} + +void pProgressBar::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/windows/widget/radio-box.cpp b/kaijuu/phoenix/windows/widget/radio-box.cpp new file mode 100644 index 00000000..ebcb1edc --- /dev/null +++ b/kaijuu/phoenix/windows/widget/radio-box.cpp @@ -0,0 +1,43 @@ +bool pRadioBox::checked() { + return SendMessage(hwnd, BM_GETCHECK, 0, 0); +} + +Geometry pRadioBox::minimumGeometry() { + Geometry geometry = pFont::geometry(hfont, radioBox.state.text); + return { 0, 0, geometry.width + 20, geometry.height + 4 }; +} + +void pRadioBox::setChecked() { + for(auto &item : radioBox.state.group) { + SendMessage(item.p.hwnd, BM_SETCHECK, (WPARAM)(&item == &radioBox), 0); + } +} + +void pRadioBox::setGroup(const set &group) { +} + +void pRadioBox::setText(const string &text) { + SetWindowText(hwnd, utf16_t(text)); +} + +void pRadioBox::constructor() { + hwnd = CreateWindow( + L"BUTTON", L"", + WS_CHILD | WS_TABSTOP | BS_RADIOBUTTON, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&radioBox); + setDefaultFont(); + if(radioBox.state.checked) setChecked(); + setText(radioBox.state.text); + synchronize(); +} + +void pRadioBox::destructor() { + DestroyWindow(hwnd); +} + +void pRadioBox::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/windows/widget/text-edit.cpp b/kaijuu/phoenix/windows/widget/text-edit.cpp new file mode 100644 index 00000000..8e1df517 --- /dev/null +++ b/kaijuu/phoenix/windows/widget/text-edit.cpp @@ -0,0 +1,58 @@ +void pTextEdit::setCursorPosition(unsigned position) { + if(position == ~0) position >>= 1; //Edit_SetSel takes signed type + Edit_SetSel(hwnd, position, position); + Edit_ScrollCaret(hwnd); +} + +void pTextEdit::setEditable(bool editable) { + SendMessage(hwnd, EM_SETREADONLY, editable == false, (LPARAM)0); +} + +void pTextEdit::setText(const string &text) { + locked = true; + string output = text; + output.replace("\r", ""); + output.replace("\n", "\r\n"); + SetWindowText(hwnd, utf16_t(output)); + locked = false; +} + +void pTextEdit::setWordWrap(bool wordWrap) { + //ES_AUTOHSCROLL cannot be changed after widget creation. + //As a result, we must destroy and re-create widget to change this setting. + orphan(); +} + +string pTextEdit::text() { + unsigned length = GetWindowTextLength(hwnd); + wchar_t buffer[length + 1]; + GetWindowText(hwnd, buffer, length + 1); + buffer[length] = 0; + string text = (const char*)utf8_t(buffer); + text.replace("\r", ""); + return text; +} + +void pTextEdit::constructor() { + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, L"EDIT", L"", + WS_CHILD | WS_TABSTOP | WS_VSCROLL | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN | (textEdit.state.wordWrap == false ? WS_HSCROLL | ES_AUTOHSCROLL : 0), + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&textEdit); + setDefaultFont(); + setCursorPosition(textEdit.state.cursorPosition); + setEditable(textEdit.state.editable); + setText(textEdit.state.text); + synchronize(); +} + +void pTextEdit::destructor() { + textEdit.state.text = text(); + DestroyWindow(hwnd); +} + +void pTextEdit::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/windows/widget/vertical-scroll-bar.cpp b/kaijuu/phoenix/windows/widget/vertical-scroll-bar.cpp new file mode 100644 index 00000000..dcc281f2 --- /dev/null +++ b/kaijuu/phoenix/windows/widget/vertical-scroll-bar.cpp @@ -0,0 +1,38 @@ +Geometry pVerticalScrollBar::minimumGeometry() { + return { 0, 0, 18, 0 }; +} + +unsigned pVerticalScrollBar::position() { + return GetScrollPos(hwnd, SB_CTL); +} + +void pVerticalScrollBar::setLength(unsigned length) { + length += (length == 0); + SetScrollRange(hwnd, SB_CTL, 0, length - 1, TRUE); + verticalScrollBar.setPosition(0); +} + +void pVerticalScrollBar::setPosition(unsigned position) { + SetScrollPos(hwnd, SB_CTL, position, TRUE); +} + +void pVerticalScrollBar::constructor() { + hwnd = CreateWindow( + L"SCROLLBAR", L"", WS_CHILD | SBS_VERT, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&verticalScrollBar); + unsigned position = verticalScrollBar.state.position; + setLength(verticalScrollBar.state.length); + verticalScrollBar.setPosition(position); + synchronize(); +} + +void pVerticalScrollBar::destructor() { + DestroyWindow(hwnd); +} + +void pVerticalScrollBar::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/windows/widget/vertical-slider.cpp b/kaijuu/phoenix/windows/widget/vertical-slider.cpp new file mode 100644 index 00000000..ac5cb1ce --- /dev/null +++ b/kaijuu/phoenix/windows/widget/vertical-slider.cpp @@ -0,0 +1,39 @@ +Geometry pVerticalSlider::minimumGeometry() { + return { 0, 0, 0, 25 }; +} + +unsigned pVerticalSlider::position() { + return SendMessage(hwnd, TBM_GETPOS, 0, 0); +} + +void pVerticalSlider::setLength(unsigned length) { + length += (length == 0); + SendMessage(hwnd, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1)); + SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3)); + verticalSlider.setPosition(0); +} + +void pVerticalSlider::setPosition(unsigned position) { + SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)position); +} + +void pVerticalSlider::constructor() { + hwnd = CreateWindow( + TRACKBAR_CLASS, L"", WS_CHILD | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_VERT, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&verticalSlider); + unsigned position = verticalSlider.state.position; + setLength(verticalSlider.state.length); + verticalSlider.setPosition(position); + synchronize(); +} + +void pVerticalSlider::destructor() { + DestroyWindow(hwnd); +} + +void pVerticalSlider::orphan() { + destructor(); + constructor(); +} diff --git a/kaijuu/phoenix/windows/widget/viewport.cpp b/kaijuu/phoenix/windows/widget/viewport.cpp new file mode 100644 index 00000000..c0b13b69 --- /dev/null +++ b/kaijuu/phoenix/windows/widget/viewport.cpp @@ -0,0 +1,57 @@ +static LRESULT CALLBACK Viewport_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + Object *object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(object == nullptr) return DefWindowProc(hwnd, msg, wparam, lparam); + if(!dynamic_cast(object)) return DefWindowProc(hwnd, msg, wparam, lparam); + Viewport &viewport = (Viewport&)*object; + + if(msg == WM_GETDLGCODE) { + return DLGC_STATIC | DLGC_WANTCHARS; + } + + if(msg == WM_MOUSEMOVE) { + TRACKMOUSEEVENT tracker = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, hwnd }; + TrackMouseEvent(&tracker); + if(viewport.onMouseMove) viewport.onMouseMove({ (int16_t)LOWORD(lparam), (int16_t)HIWORD(lparam) }); + } + + if(msg == WM_MOUSELEAVE) { + if(viewport.onMouseLeave) viewport.onMouseLeave(); + } + + if(msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) { + if(viewport.onMousePress) switch(msg) { + case WM_LBUTTONDOWN: viewport.onMousePress(Mouse::Button::Left); break; + case WM_MBUTTONDOWN: viewport.onMousePress(Mouse::Button::Middle); break; + case WM_RBUTTONDOWN: viewport.onMousePress(Mouse::Button::Right); break; + } + } + + if(msg == WM_LBUTTONUP || msg == WM_MBUTTONUP || msg == WM_RBUTTONUP) { + if(viewport.onMouseRelease) switch(msg) { + case WM_LBUTTONUP: viewport.onMouseRelease(Mouse::Button::Left); break; + case WM_MBUTTONUP: viewport.onMouseRelease(Mouse::Button::Middle); break; + case WM_RBUTTONUP: viewport.onMouseRelease(Mouse::Button::Right); break; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +uintptr_t pViewport::handle() { + return (uintptr_t)hwnd; +} + +void pViewport::constructor() { + hwnd = CreateWindow(L"phoenix_viewport", L"", WS_CHILD | WS_DISABLED, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&viewport); + synchronize(); +} + +void pViewport::destructor() { + DestroyWindow(hwnd); +} + +void pViewport::orphan() { + destructor(); + constructor(); +} \ No newline at end of file diff --git a/kaijuu/phoenix/windows/widget/widget.cpp b/kaijuu/phoenix/windows/widget/widget.cpp new file mode 100644 index 00000000..b0e60c7d --- /dev/null +++ b/kaijuu/phoenix/windows/widget/widget.cpp @@ -0,0 +1,66 @@ +bool pWidget::enabled() { + return IsWindowEnabled(hwnd); +} + +Geometry pWidget::minimumGeometry() { + return { 0, 0, 0, 0 }; +} + +void pWidget::setEnabled(bool enabled) { + if(widget.state.abstract) enabled = false; + if(sizable.state.layout && sizable.state.layout->enabled() == false) enabled = false; + EnableWindow(hwnd, enabled); +} + +void pWidget::setFocused() { + SetFocus(hwnd); +} + +void pWidget::setFont(const string &font) { + if(hfont) DeleteObject(hfont); + hfont = pFont::create(font); + SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0); +} + +void pWidget::setGeometry(const Geometry &geometry) { + SetWindowPos(hwnd, NULL, geometry.x, geometry.y, geometry.width, geometry.height, SWP_NOZORDER); +} + +void pWidget::setVisible(bool visible) { + if(widget.state.abstract) visible = false; + if(sizable.state.layout && sizable.state.layout->visible() == false) visible = false; + ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE); +} + +void pWidget::constructor() { + hfont = pFont::create("Tahoma, 8"); + if(widget.state.abstract) { + hwnd = CreateWindow(L"phoenix_label", L"", WS_CHILD, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&widget); + } +} + +void pWidget::destructor() { + if(widget.state.abstract) { + DestroyWindow(hwnd); + } +} + +void pWidget::orphan() { + destructor(); + constructor(); +} + +void pWidget::setDefaultFont() { + string description = widget.state.font; + if(description == "") description = "Tahoma, 8"; + hfont = pFont::create(description); + SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0); +} + +//calling Widget::setParent destroys widget and re-creates it: +//need to re-apply visiblity and enabled status; called by each subclassed setParent() function +void pWidget::synchronize() { + widget.setEnabled(widget.enabled()); + widget.setVisible(widget.visible()); +} diff --git a/kaijuu/phoenix/windows/window.cpp b/kaijuu/phoenix/windows/window.cpp new file mode 100644 index 00000000..dc8aea28 --- /dev/null +++ b/kaijuu/phoenix/windows/window.cpp @@ -0,0 +1,229 @@ +vector pWindow::modal; + +void pWindow::updateModality() { + for(auto &object : pObject::objects) { + if(dynamic_cast(object) == nullptr) continue; + pWindow *p = (pWindow*)object; + if(modal.size() == 0) EnableWindow(p->hwnd, true); + else EnableWindow(p->hwnd, modal.find(p)); + } +} + +static const unsigned FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER; +static const unsigned ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME; + +Window& pWindow::none() { + static Window *window = nullptr; + if(window == nullptr) window = new Window; + return *window; +} + +void pWindow::append(Layout &layout) { + Geometry geom = window.state.geometry; + geom.x = geom.y = 0; + layout.setGeometry(geom); +} + +void pWindow::append(Menu &menu) { + menu.p.parentWindow = &window; + updateMenu(); +} + +void pWindow::append(Widget &widget) { + widget.p.parentWindow = &window; + widget.p.orphan(); + if(widget.state.font != "") widget.p.setFont(widget.state.font); + else if(window.state.widgetFont != "") widget.p.setFont(window.state.widgetFont); + else widget.p.setFont("Tahoma, 8"); +} + +Color pWindow::backgroundColor() { + if(window.state.backgroundColorOverride) return window.state.backgroundColor; + DWORD color = GetSysColor(COLOR_3DFACE); + return { (uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color >> 0), 255 }; +} + +bool pWindow::focused() { + return (GetForegroundWindow() == hwnd); +} + +Geometry pWindow::frameMargin() { + unsigned style = window.state.resizable ? ResizableStyle : FixedStyle; + if(window.state.fullScreen) style = 0; + RECT rc = { 0, 0, 640, 480 }; + AdjustWindowRect(&rc, style, window.state.menuVisible); + unsigned statusHeight = 0; + if(window.state.statusVisible) { + RECT src; + GetClientRect(hstatus, &src); + statusHeight = src.bottom - src.top; + } + return { abs(rc.left), abs(rc.top), (rc.right - rc.left) - 640, (rc.bottom - rc.top) + statusHeight - 480 }; +} + +Geometry pWindow::geometry() { + Geometry margin = frameMargin(); + + RECT rc; + if(IsIconic(hwnd)) { + //GetWindowRect returns -32000(x),-32000(y) when window is minimized + WINDOWPLACEMENT wp; + GetWindowPlacement(hwnd, &wp); + rc = wp.rcNormalPosition; + } else { + GetWindowRect(hwnd, &rc); + } + + signed x = rc.left + margin.x; + signed y = rc.top + margin.y; + unsigned width = (rc.right - rc.left) - margin.width; + unsigned height = (rc.bottom - rc.top) - margin.height; + + return { x, y, width, height }; +} + +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { + updateMenu(); +} + +void pWindow::remove(Widget &widget) { + widget.p.orphan(); +} + +void pWindow::setBackgroundColor(const Color &color) { + if(brush) DeleteObject(brush); + brushColor = RGB(color.red, color.green, color.blue); + brush = CreateSolidBrush(brushColor); +} + +void pWindow::setFocused() { + if(window.state.visible == false) setVisible(true); + SetFocus(hwnd); +} + +void pWindow::setFullScreen(bool fullScreen) { + locked = true; + if(fullScreen == false) { + SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | (window.state.resizable ? ResizableStyle : FixedStyle)); + setGeometry(window.state.geometry); + } else { + SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP); + Geometry margin = frameMargin(); + setGeometry({ margin.x, margin.y, GetSystemMetrics(SM_CXSCREEN) - margin.width, GetSystemMetrics(SM_CYSCREEN) - margin.height }); + } + locked = false; +} + +void pWindow::setGeometry(const Geometry &geometry) { + locked = true; + Geometry margin = frameMargin(); + SetWindowPos( + hwnd, NULL, + geometry.x - margin.x, geometry.y - margin.y, + geometry.width + margin.width, geometry.height + margin.height, + SWP_NOZORDER | SWP_FRAMECHANGED + ); + SetWindowPos(hstatus, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED); + for(auto &layout : window.state.layout) { + Geometry geom = this->geometry(); + geom.x = geom.y = 0; + layout.setGeometry(geom); + } + locked = false; +} + +void pWindow::setMenuFont(const string &font) { +} + +void pWindow::setMenuVisible(bool visible) { + locked = true; + SetMenu(hwnd, visible ? hmenu : 0); + setGeometry(window.state.geometry); + locked = false; +} + +void pWindow::setModal(bool modality) { + if(modality == false) { + if(auto position = modal.find(this)) modal.remove(position()); + } else { + modal.appendonce(this); + } + updateModality(); +} + +void pWindow::setResizable(bool resizable) { + SetWindowLongPtr(hwnd, GWL_STYLE, window.state.resizable ? ResizableStyle : FixedStyle); + setGeometry(window.state.geometry); +} + +void pWindow::setStatusFont(const string &font) { + if(hstatusfont) DeleteObject(hstatusfont); + hstatusfont = pFont::create(font); + SendMessage(hstatus, WM_SETFONT, (WPARAM)hstatusfont, 0); +} + +void pWindow::setStatusText(const string &text) { + SendMessage(hstatus, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16_t(text)); +} + +void pWindow::setStatusVisible(bool visible) { + locked = true; + ShowWindow(hstatus, visible ? SW_SHOWNORMAL : SW_HIDE); + setGeometry(window.state.geometry); + locked = false; +} + +void pWindow::setTitle(const string &text) { + SetWindowText(hwnd, utf16_t(text)); +} + +void pWindow::setVisible(bool visible) { + ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE); + if(visible == false) setModal(false); +} + +void pWindow::setWidgetFont(const string &font) { + for(auto &widget : window.state.widget) { + if(widget.state.font == "") widget.setFont(font); + } +} + +void pWindow::constructor() { + brush = 0; + + hwnd = CreateWindow(L"phoenix_window", L"", ResizableStyle, 128, 128, 256, 256, 0, 0, GetModuleHandle(0), 0); + hmenu = CreateMenu(); + hstatus = CreateWindow(STATUSCLASSNAME, L"", WS_CHILD, 0, 0, 0, 0, hwnd, 0, GetModuleHandle(0), 0); + hstatusfont = 0; + setStatusFont("Tahoma, 8"); + + //status bar will be capable of receiving tab focus if it is not disabled + SetWindowLongPtr(hstatus, GWL_STYLE, GetWindowLong(hstatus, GWL_STYLE) | WS_DISABLED); + + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&window); + setGeometry({ 128, 128, 256, 256 }); +} + +void pWindow::destructor() { + DeleteObject(hstatusfont); + DestroyWindow(hstatus); + DestroyMenu(hmenu); + DestroyWindow(hwnd); +} + +void pWindow::updateMenu() { + if(hmenu) DestroyMenu(hmenu); + hmenu = CreateMenu(); + + for(auto &menu : window.state.menu) { + menu.p.update(window); + if(menu.visible()) { + AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT_PTR)menu.p.hmenu, utf16_t(menu.state.text)); + } + } + + SetMenu(hwnd, window.state.menuVisible ? hmenu : 0); +} diff --git a/kaijuu/resource/kaijuu.png b/kaijuu/resource/kaijuu.png new file mode 100644 index 0000000000000000000000000000000000000000..8155bd9a2c97e8b7eddfda7f6b6bcf0f1d2fd6a3 GIT binary patch literal 13013 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 + + + diff --git a/kaijuu/settings.hpp b/kaijuu/settings.hpp new file mode 100644 index 00000000..4f3387ed --- /dev/null +++ b/kaijuu/settings.hpp @@ -0,0 +1,45 @@ +struct Settings { + struct Rule { + string name; + string pattern; + bool defaultAction; + bool matchFiles; + bool matchFolders; + string command; + bool multiSelection; + }; + vector rules; + + void load() { + rules.reset(); + lstring ruleIDs = registry::contents("HKCU/Software/Kaijuu/"); + for(auto &ruleID : ruleIDs) { + string path = {"HKCU/Software/Kaijuu/", ruleID, "/"}; + rules.append({ + registry::read({path, "Name"}), + registry::read({path, "Pattern"}), + registry::read({path, "Default"}) == "true", + registry::read({path, "Files"}) == "true", + registry::read({path, "Folders"}) == "true", + registry::read({path, "Command"}), + }); + } + for(auto &rule : rules) { + rule.multiSelection = rule.command.position("{paths}") || rule.command.position("{files}"); + } + } + + void save() { + registry::remove("HKCU/Software/Kaijuu/"); + for(unsigned id = 0; id < rules.size(); id++) { + auto &rule = rules(id); + string path = {"HKCU/Software/Kaijuu/", id, "/"}; + registry::write({path, "Name"}, rule.name); + registry::write({path, "Pattern"}, rule.pattern); + registry::write({path, "Default"}, rule.defaultAction); + registry::write({path, "Files"}, rule.matchFiles); + registry::write({path, "Folders"}, rule.matchFolders); + registry::write({path, "Command"}, rule.command); + } + } +} settings; diff --git a/kaijuu/sync.sh b/kaijuu/sync.sh new file mode 100644 index 00000000..9185adcd --- /dev/null +++ b/kaijuu/sync.sh @@ -0,0 +1,7 @@ +if [ -d ./nall ]; then rm -r ./nall; fi +if [ -d ./phoenix ]; then rm -r ./phoenix; fi +cp -r ../nall ./nall +cp -r ../phoenix ./phoenix +rm -r nall/test +rm -r phoenix/nall +rm -r phoenix/test diff --git a/purify/Makefile b/purify/Makefile old mode 100755 new mode 100644 index 20df2aa2..effed65e --- a/purify/Makefile +++ b/purify/Makefile @@ -8,13 +8,13 @@ link := -s ifeq ($(platform),win) resource := resource.o - flags := -m32 -mwindows $(flags) - link := -m32 -mwindows $(flags) + flags := -mwindows $(flags) + link := -mwindows $(flags) endif all: phoenix.o $(application).o ifeq ($(platform),win) - windres --target=pe-i386 phoenix/windows/phoenix.rc $(resource) + windres phoenix/windows/phoenix.rc $(resource) endif $(cpp) -o $(application) phoenix.o $(application).o $(resource) $(link) $(phoenixlink) diff --git a/purify/nall/Makefile b/purify/nall/Makefile old mode 100755 new mode 100644 index e4b0fd1c..bbc4b029 --- a/purify/nall/Makefile +++ b/purify/nall/Makefile @@ -19,6 +19,9 @@ ifeq ($(platform),) ifeq ($(uname),) platform := win delete = del $(subst /,\,$1) + else ifneq ($(findstring Windows,$(uname)),) + platform := win + delete = del $(subst /,\,$1) else ifneq ($(findstring CYGWIN,$(uname)),) platform := win delete = del $(subst /,\,$1) diff --git a/purify/nall/algorithm.hpp b/purify/nall/algorithm.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/any.hpp b/purify/nall/any.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/atoi.hpp b/purify/nall/atoi.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/base64.hpp b/purify/nall/base64.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/bit.hpp b/purify/nall/bit.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/bmp.hpp b/purify/nall/bmp.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/bps/delta.hpp b/purify/nall/bps/delta.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/bps/linear.hpp b/purify/nall/bps/linear.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/bps/metadata.hpp b/purify/nall/bps/metadata.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/bps/patch.hpp b/purify/nall/bps/patch.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/compositor.hpp b/purify/nall/compositor.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/config.hpp b/purify/nall/config.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/crc32.hpp b/purify/nall/crc32.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/directory.hpp b/purify/nall/directory.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dl.hpp b/purify/nall/dl.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp.hpp b/purify/nall/dsp.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp/buffer.hpp b/purify/nall/dsp/buffer.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp/core.hpp b/purify/nall/dsp/core.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp/resample/average.hpp b/purify/nall/dsp/resample/average.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp/resample/cosine.hpp b/purify/nall/dsp/resample/cosine.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp/resample/cubic.hpp b/purify/nall/dsp/resample/cubic.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp/resample/hermite.hpp b/purify/nall/dsp/resample/hermite.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp/resample/lib/sinc.hpp b/purify/nall/dsp/resample/lib/sinc.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp/resample/linear.hpp b/purify/nall/dsp/resample/linear.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp/resample/nearest.hpp b/purify/nall/dsp/resample/nearest.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp/resample/sinc.hpp b/purify/nall/dsp/resample/sinc.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/dsp/settings.hpp b/purify/nall/dsp/settings.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/emulation/famicom.hpp b/purify/nall/emulation/famicom.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/emulation/game-boy-advance.hpp b/purify/nall/emulation/game-boy-advance.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/emulation/game-boy.hpp b/purify/nall/emulation/game-boy.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/emulation/satellaview.hpp b/purify/nall/emulation/satellaview.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/emulation/sufami-turbo.hpp b/purify/nall/emulation/sufami-turbo.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/emulation/super-famicom-usart.hpp b/purify/nall/emulation/super-famicom-usart.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/emulation/super-famicom.hpp b/purify/nall/emulation/super-famicom.hpp old mode 100755 new mode 100644 index 597f9893..3115d7ea --- a/purify/nall/emulation/super-famicom.hpp +++ b/purify/nall/emulation/super-famicom.hpp @@ -106,6 +106,9 @@ struct SuperFamicomCartridge { }; SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) { + //skip copier header + if((size & 0x7fff) == 512) data += 512, size -= 512; + markup = ""; if(size < 0x8000) return; diff --git a/purify/nall/endian.hpp b/purify/nall/endian.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/file.hpp b/purify/nall/file.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/filemap.hpp b/purify/nall/filemap.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/function.hpp b/purify/nall/function.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/gzip.hpp b/purify/nall/gzip.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/http.hpp b/purify/nall/http.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/image.hpp b/purify/nall/image.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/inflate.hpp b/purify/nall/inflate.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/input.hpp b/purify/nall/input.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/interpolation.hpp b/purify/nall/interpolation.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/intrinsics.hpp b/purify/nall/intrinsics.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/invoke.hpp b/purify/nall/invoke.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/ips.hpp b/purify/nall/ips.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/lzss.hpp b/purify/nall/lzss.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/map.hpp b/purify/nall/map.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/mosaic.hpp b/purify/nall/mosaic.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/mosaic/bitstream.hpp b/purify/nall/mosaic/bitstream.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/mosaic/context.hpp b/purify/nall/mosaic/context.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/mosaic/parser.hpp b/purify/nall/mosaic/parser.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/nall.hpp b/purify/nall/nall.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/platform.hpp b/purify/nall/platform.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/png.hpp b/purify/nall/png.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/priority-queue.hpp b/purify/nall/priority-queue.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/property.hpp b/purify/nall/property.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/public-cast.hpp b/purify/nall/public-cast.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/random.hpp b/purify/nall/random.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/serial.hpp b/purify/nall/serial.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/serializer.hpp b/purify/nall/serializer.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/set.hpp b/purify/nall/set.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/sha256.hpp b/purify/nall/sha256.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/sort.hpp b/purify/nall/sort.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/stdint.hpp b/purify/nall/stdint.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/stream.hpp b/purify/nall/stream.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/stream/auto.hpp b/purify/nall/stream/auto.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/stream/file.hpp b/purify/nall/stream/file.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/stream/gzip.hpp b/purify/nall/stream/gzip.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/stream/http.hpp b/purify/nall/stream/http.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/stream/memory.hpp b/purify/nall/stream/memory.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/stream/mmap.hpp b/purify/nall/stream/mmap.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/stream/stream.hpp b/purify/nall/stream/stream.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/stream/vector.hpp b/purify/nall/stream/vector.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/stream/zip.hpp b/purify/nall/stream/zip.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string.hpp b/purify/nall/string.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/base.hpp b/purify/nall/string/base.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/bml.hpp b/purify/nall/string/bml.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/bsv.hpp b/purify/nall/string/bsv.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/cast.hpp b/purify/nall/string/cast.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/compare.hpp b/purify/nall/string/compare.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/convert.hpp b/purify/nall/string/convert.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/core.hpp b/purify/nall/string/core.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/cstring.hpp b/purify/nall/string/cstring.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/filename.hpp b/purify/nall/string/filename.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/math-fixed-point.hpp b/purify/nall/string/math-fixed-point.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/math-floating-point.hpp b/purify/nall/string/math-floating-point.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/platform.hpp b/purify/nall/string/platform.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/replace.hpp b/purify/nall/string/replace.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/split.hpp b/purify/nall/string/split.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/static.hpp b/purify/nall/string/static.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/strm.hpp b/purify/nall/string/strm.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/strpos.hpp b/purify/nall/string/strpos.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/trim.hpp b/purify/nall/string/trim.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/utf8.hpp b/purify/nall/string/utf8.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/utility.hpp b/purify/nall/string/utility.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/variadic.hpp b/purify/nall/string/variadic.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/wildcard.hpp b/purify/nall/string/wildcard.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/wrapper.hpp b/purify/nall/string/wrapper.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/xml-legacy.hpp b/purify/nall/string/xml-legacy.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/string/xml.hpp b/purify/nall/string/xml.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/traits.hpp b/purify/nall/traits.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/udl.hpp b/purify/nall/udl.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/ups.hpp b/purify/nall/ups.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/utility.hpp b/purify/nall/utility.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/varint.hpp b/purify/nall/varint.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/vector.hpp b/purify/nall/vector.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/windows/detour.hpp b/purify/nall/windows/detour.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/windows/guid.hpp b/purify/nall/windows/guid.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/windows/launcher.hpp b/purify/nall/windows/launcher.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/windows/registry.hpp b/purify/nall/windows/registry.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/windows/utf8.hpp b/purify/nall/windows/utf8.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/xorg/guard.hpp b/purify/nall/xorg/guard.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/xorg/xorg.hpp b/purify/nall/xorg/xorg.hpp old mode 100755 new mode 100644 diff --git a/purify/nall/zip.hpp b/purify/nall/zip.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/Makefile b/purify/phoenix/Makefile old mode 100755 new mode 100644 diff --git a/purify/phoenix/core/core.cpp b/purify/phoenix/core/core.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/core/core.hpp b/purify/phoenix/core/core.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/core/keyboard.hpp b/purify/phoenix/core/keyboard.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/core/layout/fixed-layout.cpp b/purify/phoenix/core/layout/fixed-layout.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/core/layout/fixed-layout.hpp b/purify/phoenix/core/layout/fixed-layout.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/core/layout/horizontal-layout.cpp b/purify/phoenix/core/layout/horizontal-layout.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/core/layout/horizontal-layout.hpp b/purify/phoenix/core/layout/horizontal-layout.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/core/layout/vertical-layout.cpp b/purify/phoenix/core/layout/vertical-layout.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/core/layout/vertical-layout.hpp b/purify/phoenix/core/layout/vertical-layout.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/core/state.hpp b/purify/phoenix/core/state.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/action/action.cpp b/purify/phoenix/gtk/action/action.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/action/check-item.cpp b/purify/phoenix/gtk/action/check-item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/action/item.cpp b/purify/phoenix/gtk/action/item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/action/menu.cpp b/purify/phoenix/gtk/action/menu.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/action/radio-item.cpp b/purify/phoenix/gtk/action/radio-item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/action/separator.cpp b/purify/phoenix/gtk/action/separator.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/desktop.cpp b/purify/phoenix/gtk/desktop.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/dialog-window.cpp b/purify/phoenix/gtk/dialog-window.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/font.cpp b/purify/phoenix/gtk/font.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/keyboard.cpp b/purify/phoenix/gtk/keyboard.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/message-window.cpp b/purify/phoenix/gtk/message-window.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/mouse.cpp b/purify/phoenix/gtk/mouse.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/platform.cpp b/purify/phoenix/gtk/platform.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/platform.hpp b/purify/phoenix/gtk/platform.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/settings.cpp b/purify/phoenix/gtk/settings.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/timer.cpp b/purify/phoenix/gtk/timer.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/utility.cpp b/purify/phoenix/gtk/utility.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/button.cpp b/purify/phoenix/gtk/widget/button.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/canvas.cpp b/purify/phoenix/gtk/widget/canvas.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/check-box.cpp b/purify/phoenix/gtk/widget/check-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/combo-box.cpp b/purify/phoenix/gtk/widget/combo-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/hex-edit.cpp b/purify/phoenix/gtk/widget/hex-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/horizontal-scroll-bar.cpp b/purify/phoenix/gtk/widget/horizontal-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/horizontal-slider.cpp b/purify/phoenix/gtk/widget/horizontal-slider.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/label.cpp b/purify/phoenix/gtk/widget/label.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/line-edit.cpp b/purify/phoenix/gtk/widget/line-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/list-view.cpp b/purify/phoenix/gtk/widget/list-view.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/progress-bar.cpp b/purify/phoenix/gtk/widget/progress-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/radio-box.cpp b/purify/phoenix/gtk/widget/radio-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/text-edit.cpp b/purify/phoenix/gtk/widget/text-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/vertical-scroll-bar.cpp b/purify/phoenix/gtk/widget/vertical-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/vertical-slider.cpp b/purify/phoenix/gtk/widget/vertical-slider.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/viewport.cpp b/purify/phoenix/gtk/widget/viewport.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/widget/widget.cpp b/purify/phoenix/gtk/widget/widget.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/gtk/window.cpp b/purify/phoenix/gtk/window.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/phoenix.cpp b/purify/phoenix/phoenix.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/phoenix.hpp b/purify/phoenix/phoenix.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/action/action.cpp b/purify/phoenix/qt/action/action.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/action/check-item.cpp b/purify/phoenix/qt/action/check-item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/action/item.cpp b/purify/phoenix/qt/action/item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/action/menu.cpp b/purify/phoenix/qt/action/menu.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/action/radio-item.cpp b/purify/phoenix/qt/action/radio-item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/action/separator.cpp b/purify/phoenix/qt/action/separator.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/desktop.cpp b/purify/phoenix/qt/desktop.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/dialog-window.cpp b/purify/phoenix/qt/dialog-window.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/font.cpp b/purify/phoenix/qt/font.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/keyboard.cpp b/purify/phoenix/qt/keyboard.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/message-window.cpp b/purify/phoenix/qt/message-window.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/mouse.cpp b/purify/phoenix/qt/mouse.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/platform.cpp b/purify/phoenix/qt/platform.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/platform.moc b/purify/phoenix/qt/platform.moc old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/platform.moc.hpp b/purify/phoenix/qt/platform.moc.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/settings.cpp b/purify/phoenix/qt/settings.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/timer.cpp b/purify/phoenix/qt/timer.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/utility.cpp b/purify/phoenix/qt/utility.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/button.cpp b/purify/phoenix/qt/widget/button.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/canvas.cpp b/purify/phoenix/qt/widget/canvas.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/check-box.cpp b/purify/phoenix/qt/widget/check-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/combo-box.cpp b/purify/phoenix/qt/widget/combo-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/hex-edit.cpp b/purify/phoenix/qt/widget/hex-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/horizontal-scroll-bar.cpp b/purify/phoenix/qt/widget/horizontal-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/horizontal-slider.cpp b/purify/phoenix/qt/widget/horizontal-slider.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/label.cpp b/purify/phoenix/qt/widget/label.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/line-edit.cpp b/purify/phoenix/qt/widget/line-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/list-view.cpp b/purify/phoenix/qt/widget/list-view.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/progress-bar.cpp b/purify/phoenix/qt/widget/progress-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/radio-box.cpp b/purify/phoenix/qt/widget/radio-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/text-edit.cpp b/purify/phoenix/qt/widget/text-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/vertical-scroll-bar.cpp b/purify/phoenix/qt/widget/vertical-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/vertical-slider.cpp b/purify/phoenix/qt/widget/vertical-slider.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/viewport.cpp b/purify/phoenix/qt/widget/viewport.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/widget/widget.cpp b/purify/phoenix/qt/widget/widget.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/qt/window.cpp b/purify/phoenix/qt/window.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/action/action.cpp b/purify/phoenix/reference/action/action.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/action/check-item.cpp b/purify/phoenix/reference/action/check-item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/action/item.cpp b/purify/phoenix/reference/action/item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/action/menu.cpp b/purify/phoenix/reference/action/menu.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/action/radio-item.cpp b/purify/phoenix/reference/action/radio-item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/action/separator.cpp b/purify/phoenix/reference/action/separator.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/desktop.cpp b/purify/phoenix/reference/desktop.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/dialog-window.cpp b/purify/phoenix/reference/dialog-window.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/font.cpp b/purify/phoenix/reference/font.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/keyboard.cpp b/purify/phoenix/reference/keyboard.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/message-window.cpp b/purify/phoenix/reference/message-window.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/mouse.cpp b/purify/phoenix/reference/mouse.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/platform.cpp b/purify/phoenix/reference/platform.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/platform.hpp b/purify/phoenix/reference/platform.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/timer.cpp b/purify/phoenix/reference/timer.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/button.cpp b/purify/phoenix/reference/widget/button.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/canvas.cpp b/purify/phoenix/reference/widget/canvas.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/check-box.cpp b/purify/phoenix/reference/widget/check-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/combo-box.cpp b/purify/phoenix/reference/widget/combo-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/hex-edit.cpp b/purify/phoenix/reference/widget/hex-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/horizontal-scroll-bar.cpp b/purify/phoenix/reference/widget/horizontal-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/horizontal-slider.cpp b/purify/phoenix/reference/widget/horizontal-slider.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/label.cpp b/purify/phoenix/reference/widget/label.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/line-edit.cpp b/purify/phoenix/reference/widget/line-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/list-view.cpp b/purify/phoenix/reference/widget/list-view.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/progress-bar.cpp b/purify/phoenix/reference/widget/progress-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/radio-box.cpp b/purify/phoenix/reference/widget/radio-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/text-edit.cpp b/purify/phoenix/reference/widget/text-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/vertical-scroll-bar.cpp b/purify/phoenix/reference/widget/vertical-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/vertical-slider.cpp b/purify/phoenix/reference/widget/vertical-slider.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/viewport.cpp b/purify/phoenix/reference/widget/viewport.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/widget/widget.cpp b/purify/phoenix/reference/widget/widget.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/reference/window.cpp b/purify/phoenix/reference/window.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/sync.sh b/purify/phoenix/sync.sh old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/action/action.cpp b/purify/phoenix/windows/action/action.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/action/check-item.cpp b/purify/phoenix/windows/action/check-item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/action/item.cpp b/purify/phoenix/windows/action/item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/action/menu.cpp b/purify/phoenix/windows/action/menu.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/action/radio-item.cpp b/purify/phoenix/windows/action/radio-item.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/action/separator.cpp b/purify/phoenix/windows/action/separator.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/desktop.cpp b/purify/phoenix/windows/desktop.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/dialog-window.cpp b/purify/phoenix/windows/dialog-window.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/font.cpp b/purify/phoenix/windows/font.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/keyboard.cpp b/purify/phoenix/windows/keyboard.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/message-window.cpp b/purify/phoenix/windows/message-window.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/mouse.cpp b/purify/phoenix/windows/mouse.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/object.cpp b/purify/phoenix/windows/object.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/phoenix.Manifest b/purify/phoenix/windows/phoenix.Manifest old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/phoenix.rc b/purify/phoenix/windows/phoenix.rc old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/platform.cpp b/purify/phoenix/windows/platform.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/platform.hpp b/purify/phoenix/windows/platform.hpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/settings.cpp b/purify/phoenix/windows/settings.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/timer.cpp b/purify/phoenix/windows/timer.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/utility.cpp b/purify/phoenix/windows/utility.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/button.cpp b/purify/phoenix/windows/widget/button.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/canvas.cpp b/purify/phoenix/windows/widget/canvas.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/check-box.cpp b/purify/phoenix/windows/widget/check-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/combo-box.cpp b/purify/phoenix/windows/widget/combo-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/hex-edit.cpp b/purify/phoenix/windows/widget/hex-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/horizontal-scroll-bar.cpp b/purify/phoenix/windows/widget/horizontal-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/horizontal-slider.cpp b/purify/phoenix/windows/widget/horizontal-slider.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/label.cpp b/purify/phoenix/windows/widget/label.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/line-edit.cpp b/purify/phoenix/windows/widget/line-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/list-view.cpp b/purify/phoenix/windows/widget/list-view.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/progress-bar.cpp b/purify/phoenix/windows/widget/progress-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/radio-box.cpp b/purify/phoenix/windows/widget/radio-box.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/text-edit.cpp b/purify/phoenix/windows/widget/text-edit.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/vertical-scroll-bar.cpp b/purify/phoenix/windows/widget/vertical-scroll-bar.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/vertical-slider.cpp b/purify/phoenix/windows/widget/vertical-slider.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/viewport.cpp b/purify/phoenix/windows/widget/viewport.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/widget/widget.cpp b/purify/phoenix/windows/widget/widget.cpp old mode 100755 new mode 100644 diff --git a/purify/phoenix/windows/window.cpp b/purify/phoenix/windows/window.cpp old mode 100755 new mode 100644 diff --git a/purify/purify.cpp b/purify/purify.cpp old mode 100755 new mode 100644 index 53575093..5d05c1d6 --- a/purify/purify.cpp +++ b/purify/purify.cpp @@ -406,7 +406,7 @@ struct Application : Window { Button synchronizeButton; Application() { - setTitle("purify v00.07"); + setTitle("purify v01"); setGeometry({128, 128, 600, 200}); layout.setMargin(5); title.setFont("Sans, 16, Bold"); diff --git a/purify/resource/applications-system.png b/purify/resource/applications-system.png old mode 100755 new mode 100644 diff --git a/purify/resource/drive-harddisk.png b/purify/resource/drive-harddisk.png old mode 100755 new mode 100644 diff --git a/purify/resource/folder.png b/purify/resource/folder.png old mode 100755 new mode 100644 diff --git a/purify/resource/input-gaming.png b/purify/resource/input-gaming.png old mode 100755 new mode 100644 diff --git a/purify/resource/resource.cpp b/purify/resource/resource.cpp old mode 100755 new mode 100644 diff --git a/purify/resource/resource.hpp b/purify/resource/resource.hpp old mode 100755 new mode 100644 diff --git a/purify/resource/resource.xml b/purify/resource/resource.xml old mode 100755 new mode 100644 diff --git a/purify/resource/view-refresh.png b/purify/resource/view-refresh.png old mode 100755 new mode 100644 diff --git a/snesfilter/HQ2x/HQ2x-RGB555.cpp b/snesfilter/HQ2x/HQ2x-RGB555.cpp deleted file mode 100755 index 89aa1e70..00000000 --- a/snesfilter/HQ2x/HQ2x-RGB555.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include -#include -using namespace nall; - -extern "C" { - void filter_size(unsigned&, unsigned&); - void filter_render(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned); -}; - -enum { - diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407, - diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0, -}; - -uint32_t *yuvTable; -uint8_t rotate[256]; - -const uint8_t hqTable[256] = { - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13, - 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14, - 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14, - 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14, -}; - -static void initialize() { - static bool initialized = false; - if(initialized == true) return; - initialized = true; - - yuvTable = new uint32_t[32768]; - - for(unsigned i = 0; i < 32768; i++) { - uint8_t R = (i >> 0) & 31; - uint8_t G = (i >> 5) & 31; - uint8_t B = (i >> 10) & 31; - - //bgr555->bgr888 - double r = (R << 3) | (R >> 2); - double g = (G << 3) | (G >> 2); - double b = (B << 3) | (B >> 2); - - //bgr888->yuv - double y = (r + g + b) * (0.25f * (63.5f / 48.0f)); - double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f); - double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f); - - yuvTable[i] = ((unsigned)y << 21) + ((unsigned)u << 11) + ((unsigned)v); - } - - //counter-clockwise rotation table; one revolution: - //123 369 12346789 - //4.6 -> 2.8 = - //789 147 36928147 - for(unsigned n = 0; n < 256; n++) { - rotate[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88) - | ((n & 0x01) << 5) | ((n & 0x08) << 3) - | ((n & 0x10) >> 3) | ((n & 0x80) >> 5); - } -} - -static void terminate() { - delete[] yuvTable; -} - -static bool same(uint16_t x, uint16_t y) { - return !((yuvTable[x] - yuvTable[y] + diff_offset) & diff_mask); -} - -static bool diff(uint32_t x, uint16_t y) { - return ((x - yuvTable[y]) & diff_mask); -} - -static void grow(uint32_t &n) { n |= n << 16; n &= 0x03e07c1f; } -static uint16_t pack(uint32_t n) { n &= 0x03e07c1f; return n | (n >> 16); } - -static uint16_t blend1(uint32_t A, uint32_t B) { - grow(A); grow(B); - return pack((A * 3 + B) >> 2); -} - -static uint16_t blend2(uint32_t A, uint32_t B, uint32_t C) { - grow(A); grow(B); grow(C); - return pack((A * 2 + B + C) >> 2); -} - -static uint16_t blend3(uint32_t A, uint32_t B, uint32_t C) { - grow(A); grow(B); grow(C); - return pack((A * 5 + B * 2 + C) >> 3); -} - -static uint16_t blend4(uint32_t A, uint32_t B, uint32_t C) { - grow(A); grow(B); grow(C); - return pack((A * 6 + B + C) >> 3); -} - -static uint16_t blend5(uint32_t A, uint32_t B, uint32_t C) { - grow(A); grow(B); grow(C); - return pack((A * 2 + (B + C) * 3) >> 3); -} - -static uint16_t blend6(uint32_t A, uint32_t B, uint32_t C) { - grow(A); grow(B); grow(C); - return pack((A * 14 + B + C) >> 4); -} - -static uint16_t blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H) { - switch(rule) { default: - case 0: return E; - case 1: return blend1(E, A); - case 2: return blend1(E, D); - case 3: return blend1(E, B); - case 4: return blend2(E, D, B); - case 5: return blend2(E, A, B); - case 6: return blend2(E, A, D); - case 7: return blend3(E, B, D); - case 8: return blend3(E, D, B); - case 9: return blend4(E, D, B); - case 10: return blend5(E, D, B); - case 11: return blend6(E, D, B); - case 12: return same(B, D) ? blend2(E, D, B) : E; - case 13: return same(B, D) ? blend5(E, D, B) : E; - case 14: return same(B, D) ? blend6(E, D, B) : E; - case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A); - case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A); - case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A); - case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D); - case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B); - } -} - -dllexport void filter_size(unsigned &width, unsigned &height) { - initialize(); - width *= 2; - height *= 2; -} - -dllexport void filter_render( - uint16_t *output, unsigned outputPitch, - const uint16_t *input, unsigned inputPitch, - unsigned width, unsigned height -) { - initialize(); - outputPitch >>= 1, inputPitch >>= 1; - - #pragma omp parallel for - for(unsigned y = 0; y < height; y++) { - const uint16_t *in = input + y * inputPitch; - uint16_t *out0 = output + y * outputPitch * 2; - uint16_t *out1 = output + y * outputPitch * 2 + outputPitch; - - int prevline = (y == 0 ? 0 : inputPitch); - int nextline = (y == height - 1 ? 0 : inputPitch); - - in++; - *out0++ = 0; *out0++ = 0; - *out1++ = 0; *out1++ = 0; - - for(unsigned x = 1; x < width - 1; x++) { - uint16_t A = *(in - prevline - 1); - uint16_t B = *(in - prevline + 0); - uint16_t C = *(in - prevline + 1); - uint16_t D = *(in - 1); - uint16_t E = *(in + 0); - uint16_t F = *(in + 1); - uint16_t G = *(in + nextline - 1); - uint16_t H = *(in + nextline + 0); - uint16_t I = *(in + nextline + 1); - uint32_t e = yuvTable[E] + diff_offset; - - uint8_t pattern; - pattern = diff(e, A) << 0; - pattern |= diff(e, B) << 1; - pattern |= diff(e, C) << 2; - pattern |= diff(e, D) << 3; - pattern |= diff(e, F) << 4; - pattern |= diff(e, G) << 5; - pattern |= diff(e, H) << 6; - pattern |= diff(e, I) << 7; - - *(out0 + 0) = blend(hqTable[pattern], E, A, B, D, F, H); pattern = rotate[pattern]; - *(out0 + 1) = blend(hqTable[pattern], E, C, F, B, H, D); pattern = rotate[pattern]; - *(out1 + 1) = blend(hqTable[pattern], E, I, H, F, D, B); pattern = rotate[pattern]; - *(out1 + 0) = blend(hqTable[pattern], E, G, D, H, B, F); - - in++; - out0 += 2; - out1 += 2; - } - - in++; - *out0++ = 0; *out0++ = 0; - *out1++ = 0; *out1++ = 0; - } -} diff --git a/snesfilter/HQ2x/HQ2x.cpp b/snesfilter/HQ2x/HQ2x.cpp deleted file mode 100755 index 4d19d872..00000000 --- a/snesfilter/HQ2x/HQ2x.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include -#include -using namespace nall; - -extern "C" { - void filter_size(unsigned&, unsigned&); - void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned); -}; - -enum { - diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407, - diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0, -}; - -uint32_t *yuvTable; -uint8_t rotate[256]; - -const uint8_t hqTable[256] = { - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13, - 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14, - 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14, - 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14, - 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14, -}; - -static uint16_t rgb15(uint32_t C) { - return ((C >> 15) & 0x7c00) + ((C >> 10) & 0x03e0) + ((C >> 5) & 0x001f); -} - -static uint32_t rgb30(uint16_t C) { - return ((C & 0x7c00) << 15) + ((C & 0x7c00) << 10) - + ((C & 0x03e0) << 10) + ((C & 0x03e0) << 5) - + ((C & 0x001f) << 5) + ((C & 0x001f) << 0); -} - -static void initialize() { - static bool initialized = false; - if(initialized == true) return; - initialized = true; - - yuvTable = new uint32_t[32768]; - - for(unsigned i = 0; i < 32768; i++) { - uint8_t R = (i >> 10) & 31; - uint8_t G = (i >> 5) & 31; - uint8_t B = (i >> 0) & 31; - - double r = (R << 3) | (R >> 2); - double g = (G << 3) | (G >> 2); - double b = (B << 3) | (B >> 2); - - double y = (r + g + b) * (0.25f * (63.5f / 48.0f)); - double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f); - double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f); - - yuvTable[i] = ((unsigned)y << 21) + ((unsigned)u << 11) + ((unsigned)v); - } - - //counter-clockwise rotation table; one revolution: - //123 369 12346789 - //4.6 -> 2.8 = - //789 147 36928147 - for(unsigned n = 0; n < 256; n++) { - rotate[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88) - | ((n & 0x01) << 5) | ((n & 0x08) << 3) - | ((n & 0x10) >> 3) | ((n & 0x80) >> 5); - } -} - -static void terminate() { - delete[] yuvTable; -} - -static bool same(uint16_t x, uint16_t y) { - return !((yuvTable[x] - yuvTable[y] + diff_offset) & diff_mask); -} - -static bool diff(uint32_t x, uint16_t y) { - return ((x - yuvTable[y]) & diff_mask); -} - -static void grow(uint32_t &n) { n |= n << 16; n &= 0x03e07c1f; } -static uint16_t pack(uint32_t n) { n &= 0x03e07c1f; return n | (n >> 16); } - -static uint16_t blend1(uint32_t A, uint32_t B) { - grow(A); grow(B); - return pack((A * 3 + B) >> 2); -} - -static uint16_t blend2(uint32_t A, uint32_t B, uint32_t C) { - grow(A); grow(B); grow(C); - return pack((A * 2 + B + C) >> 2); -} - -static uint16_t blend3(uint32_t A, uint32_t B, uint32_t C) { - grow(A); grow(B); grow(C); - return pack((A * 5 + B * 2 + C) >> 3); -} - -static uint16_t blend4(uint32_t A, uint32_t B, uint32_t C) { - grow(A); grow(B); grow(C); - return pack((A * 6 + B + C) >> 3); -} - -static uint16_t blend5(uint32_t A, uint32_t B, uint32_t C) { - grow(A); grow(B); grow(C); - return pack((A * 2 + (B + C) * 3) >> 3); -} - -static uint16_t blend6(uint32_t A, uint32_t B, uint32_t C) { - grow(A); grow(B); grow(C); - return pack((A * 14 + B + C) >> 4); -} - -static uint16_t blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H) { - switch(rule) { default: - case 0: return E; - case 1: return blend1(E, A); - case 2: return blend1(E, D); - case 3: return blend1(E, B); - case 4: return blend2(E, D, B); - case 5: return blend2(E, A, B); - case 6: return blend2(E, A, D); - case 7: return blend3(E, B, D); - case 8: return blend3(E, D, B); - case 9: return blend4(E, D, B); - case 10: return blend5(E, D, B); - case 11: return blend6(E, D, B); - case 12: return same(B, D) ? blend2(E, D, B) : E; - case 13: return same(B, D) ? blend5(E, D, B) : E; - case 14: return same(B, D) ? blend6(E, D, B) : E; - case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A); - case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A); - case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A); - case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D); - case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B); - } -} - -dllexport void filter_size(unsigned &width, unsigned &height) { - initialize(); - width *= 2; - height *= 2; -} - -dllexport void filter_render( - uint32_t *output, unsigned outputPitch, - const uint32_t *input, unsigned inputPitch, - unsigned width, unsigned height -) { - initialize(); - outputPitch >>= 2, inputPitch >>= 2; - - #pragma omp parallel for - for(unsigned y = 0; y < height; y++) { - const uint32_t *in = input + y * inputPitch; - uint32_t *out0 = output + y * outputPitch * 2; - uint32_t *out1 = output + y * outputPitch * 2 + outputPitch; - - int prevline = (y == 0 ? 0 : inputPitch); - int nextline = (y == height - 1 ? 0 : inputPitch); - - in++; - *out0++ = 0; *out0++ = 0; - *out1++ = 0; *out1++ = 0; - - for(unsigned x = 1; x < width - 1; x++) { - uint16_t A = rgb15(*(in - prevline - 1)); - uint16_t B = rgb15(*(in - prevline + 0)); - uint16_t C = rgb15(*(in - prevline + 1)); - uint16_t D = rgb15(*(in - 1)); - uint16_t E = rgb15(*(in + 0)); - uint16_t F = rgb15(*(in + 1)); - uint16_t G = rgb15(*(in + nextline - 1)); - uint16_t H = rgb15(*(in + nextline + 0)); - uint16_t I = rgb15(*(in + nextline + 1)); - uint32_t e = yuvTable[E] + diff_offset; - - uint8_t pattern; - pattern = diff(e, A) << 0; - pattern |= diff(e, B) << 1; - pattern |= diff(e, C) << 2; - pattern |= diff(e, D) << 3; - pattern |= diff(e, F) << 4; - pattern |= diff(e, G) << 5; - pattern |= diff(e, H) << 6; - pattern |= diff(e, I) << 7; - - *(out0 + 0) = rgb30(blend(hqTable[pattern], E, A, B, D, F, H)); pattern = rotate[pattern]; - *(out0 + 1) = rgb30(blend(hqTable[pattern], E, C, F, B, H, D)); pattern = rotate[pattern]; - *(out1 + 1) = rgb30(blend(hqTable[pattern], E, I, H, F, D, B)); pattern = rotate[pattern]; - *(out1 + 0) = rgb30(blend(hqTable[pattern], E, G, D, H, B, F)); - - in++; - out0 += 2; - out1 += 2; - } - - in++; - *out0++ = 0; *out0++ = 0; - *out1++ = 0; *out1++ = 0; - } -} diff --git a/snesfilter/LQ2x/LQ2x.cpp b/snesfilter/LQ2x/LQ2x.cpp deleted file mode 100755 index 29d17cff..00000000 --- a/snesfilter/LQ2x/LQ2x.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -using namespace nall; - -extern "C" { - void filter_size(unsigned&, unsigned&); - void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned); -}; - -dllexport void filter_size(unsigned &width, unsigned &height) { - width *= 2; - height *= 2; -} - -dllexport void filter_render( - uint32_t *output, unsigned outputPitch, - const uint32_t *input, unsigned inputPitch, - unsigned width, unsigned height -) { - enum : unsigned { Mask = (1 << 20) | (1 << 10) | (1 << 0) }; - outputPitch >>= 2, inputPitch >>= 2; - - #pragma omp parallel for - for(unsigned y = 0; y < height; y++) { - const uint32_t *in = input + y * inputPitch; - uint32_t *out0 = output + y * outputPitch * 2; - uint32_t *out1 = output + y * outputPitch * 2 + outputPitch; - - int prevline = (y == 0 ? 0 : inputPitch); - int nextline = (y == height - 1 ? 0 : inputPitch); - - for(unsigned x = 0; x < width; x++) { - uint32_t A = *(in - prevline); - uint32_t B = (x > 0) ? *(in - 1) : *in; - uint32_t C = *in; - uint32_t D = (x < width - 1) ? *(in + 1) : *in; - uint32_t E = *(in++ + nextline); - - if(A != E && B != D) { - *out0++ = (A == B ? C + A - ((C ^ A) & Mask) >> 1 : C); - *out0++ = (A == D ? C + A - ((C ^ A) & Mask) >> 1 : C); - *out1++ = (E == B ? C + E - ((C ^ E) & Mask) >> 1 : C); - *out1++ = (E == D ? C + E - ((C ^ E) & Mask) >> 1 : C); - } else { - *out0++ = C; - *out0++ = C; - *out1++ = C; - *out1++ = C; - } - } - } -} diff --git a/snesfilter/Makefile b/snesfilter/Makefile deleted file mode 100755 index 24875c36..00000000 --- a/snesfilter/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -include nall/Makefile - -c := $(compiler) -std=gnu99 -cpp := $(subst cc,++,$(compiler)) -std=gnu++0x -flags := -fPIC -I. -Iobj -O3 -fomit-frame-pointer -link := -s -objects := - -ifeq ($(platform),x) -# flags += -fopenmp -endif - -objects += out/Pixellate2x.filter -objects += out/Scanline-Dark.filter -objects += out/Scanline-Light.filter -objects += out/Scale2x.filter -objects += out/LQ2x.filter -objects += out/HQ2x.filter -objects += out/Phosphor3x.filter - -compile = $(cpp) $(link) $(flags) -o $@ -shared $< - -%.filter: $<; $(call compile) - -all: build; - -out/Pixellate2x.filter: Pixellate2x/Pixellate2x.cpp Pixellate2x/* -out/Scanline-Dark.filter: Scanline/Scanline-Dark.cpp Scanline/* -out/Scanline-Light.filter: Scanline/Scanline-Light.cpp Scanline/* -out/Scale2x.filter: Scale2x/Scale2x.cpp Scale2x/* -out/LQ2x.filter: LQ2x/LQ2x.cpp LQ2x/* -out/HQ2x.filter: HQ2x/HQ2x.cpp HQ2x/* -out/Phosphor3x.filter: Phosphor3x/Phosphor3x.cpp Phosphor3x/* - -build: $(objects) - -install: - mkdir -p ~/.config/bsnes/filters - chmod 777 ~/.config/bsnes/filters - cp out/*.filter ~/.config/bsnes/filters - -clean: - rm out/*.filter diff --git a/snesfilter/Phosphor3x/Phosphor3x.cpp b/snesfilter/Phosphor3x/Phosphor3x.cpp deleted file mode 100755 index 69480e8c..00000000 --- a/snesfilter/Phosphor3x/Phosphor3x.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -using namespace nall; - -extern "C" { - void filter_size(unsigned&, unsigned&); - void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned); -}; - -dllexport void filter_size(unsigned &width, unsigned &height) { - width *= 3; - height *= 3; -} - -dllexport void filter_render( - uint32_t *output, unsigned outputPitch, - const uint32_t *input, unsigned inputPitch, - unsigned width, unsigned height -) { - enum : unsigned { Mask = (1022 << 20) + (1022 << 10) + (1022 << 0) }; - outputPitch >>= 2, inputPitch >>= 2; - - #pragma omp parallel for - for(unsigned y = 0; y < height; y++) { - const uint32_t *in = input + y * inputPitch; - uint32_t *out0 = output + y * outputPitch * 3; - uint32_t *out1 = output + y * outputPitch * 3 + outputPitch; - uint32_t *out2 = output + y * outputPitch * 3 + outputPitch + outputPitch; - - for(unsigned x = 0; x < width; x++) { - uint32_t A = (x == 0 ? 0 : *(in - 1)); - uint32_t B = *in; - uint32_t C = (x == width - 1 ? 0 : *(in + 1)); - - unsigned Ar = (A >> 20) & 1023, Ag = (A >> 10) & 1023, Ab = (A >> 0) & 1023; - unsigned Br = (B >> 20) & 1023, Bg = (B >> 10) & 1023, Bb = (B >> 0) & 1023; - unsigned Cr = (C >> 20) & 1023, Cg = (C >> 10) & 1023, Cb = (C >> 0) & 1023; - - A = ((Br >> 0) << 20) + ((Bg >> 1) << 10) + ((Ab >> 1) << 0); - B = ((Br >> 1) << 20) + ((Bg >> 0) << 10) + ((Bb >> 1) << 0); - C = ((Cr >> 1) << 20) + ((Bg >> 1) << 10) + ((Bb >> 0) << 0); - - in++; - - *out0++ = A; - *out1++ = A; - *out2++ = (A & Mask) >> 1; - - *out0++ = B; - *out1++ = B; - *out2++ = (B & Mask) >> 1; - - *out0++ = C; - *out1++ = C; - *out2++ = (C & Mask) >> 1; - } - } -} diff --git a/snesfilter/Pixellate2x/Pixellate2x.cpp b/snesfilter/Pixellate2x/Pixellate2x.cpp deleted file mode 100755 index 0376d191..00000000 --- a/snesfilter/Pixellate2x/Pixellate2x.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -using namespace nall; - -extern "C" { - void filter_size(unsigned&, unsigned&); - void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned); -}; - -dllexport void filter_size(unsigned &width, unsigned &height) { - width *= 2; - height *= 2; -} - -dllexport void filter_render( - uint32_t *output, unsigned outputPitch, - const uint32_t *input, unsigned inputPitch, - unsigned width, unsigned height -) { - outputPitch >>= 2, inputPitch >>= 2; - - #pragma omp parallel for - for(unsigned y = 0; y < height; y++) { - const uint32_t *in = input + y * inputPitch; - uint32_t *out0 = output + y * outputPitch * 2; - uint32_t *out1 = output + y * outputPitch * 2 + outputPitch; - - for(unsigned x = 0; x < width; x++) { - uint32_t pixel = *in++; - *out0++ = pixel; - *out0++ = pixel; - *out1++ = pixel; - *out1++ = pixel; - } - } -} diff --git a/snesfilter/Scale2x/Scale2x.cpp b/snesfilter/Scale2x/Scale2x.cpp deleted file mode 100755 index 6e5025dc..00000000 --- a/snesfilter/Scale2x/Scale2x.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -using namespace nall; - -extern "C" { - void filter_size(unsigned&, unsigned&); - void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned); -}; - -dllexport void filter_size(unsigned &width, unsigned &height) { - width *= 2; - height *= 2; -} - -dllexport void filter_render( - uint32_t *output, unsigned outputPitch, - const uint32_t *input, unsigned inputPitch, - unsigned width, unsigned height -) { - outputPitch >>= 2, inputPitch >>= 2; - - #pragma omp parallel for - for(unsigned y = 0; y < height; y++) { - const uint32_t *in = input + y * inputPitch; - uint32_t *out0 = output + y * outputPitch * 2; - uint32_t *out1 = output + y * outputPitch * 2 + outputPitch; - - int prevline = (y == 0 ? 0 : inputPitch); - int nextline = (y == height - 1 ? 0 : inputPitch); - - for(unsigned x = 0; x < width; x++) { - uint32_t A = *(in - prevline); - uint32_t B = (x > 0) ? *(in - 1) : *in; - uint32_t C = *in; - uint32_t D = (x < width - 1) ? *(in + 1) : *in; - uint32_t E = *(in++ + nextline); - - if(A != E && B != D) { - *out0++ = (A == B ? A : C); - *out0++ = (A == D ? A : C); - *out1++ = (E == B ? E : C); - *out1++ = (E == D ? E : C); - } else { - *out0++ = C; - *out0++ = C; - *out1++ = C; - *out1++ = C; - } - } - } -} diff --git a/snesfilter/Scanline/Scanline-Dark.cpp b/snesfilter/Scanline/Scanline-Dark.cpp deleted file mode 100755 index 8ff69e40..00000000 --- a/snesfilter/Scanline/Scanline-Dark.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include -using namespace nall; - -extern "C" { - void filter_size(unsigned&, unsigned&); - void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned); -}; - -dllexport void filter_size(unsigned &width, unsigned &height) { - height *= 2; -} - -dllexport void filter_render( - uint32_t *output, unsigned outputPitch, - const uint32_t *input, unsigned inputPitch, - unsigned width, unsigned height -) { - outputPitch >>= 2, inputPitch >>= 2; - - #pragma omp parallel for - for(unsigned y = 0; y < height; y++) { - const uint32_t *in = input + y * inputPitch; - uint32_t *out0 = output + y * outputPitch * 2; - uint32_t *out1 = output + y * outputPitch * 2 + outputPitch; - - for(unsigned x = 0; x < width; x++) { - *out0++ = *in++; - *out1++ = 0; - } - } -} diff --git a/snesfilter/Scanline/Scanline-Light.cpp b/snesfilter/Scanline/Scanline-Light.cpp deleted file mode 100755 index 5ce4e1b9..00000000 --- a/snesfilter/Scanline/Scanline-Light.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -using namespace nall; - -extern "C" { - void filter_size(unsigned&, unsigned&); - void filter_render(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned); -}; - -dllexport void filter_size(unsigned &width, unsigned &height) { - height *= 2; -} - -dllexport void filter_render( - uint32_t *output, unsigned outputPitch, - const uint32_t *input, unsigned inputPitch, - unsigned width, unsigned height -) { - enum : unsigned { Mask = (1022 << 20) | (1022 << 10) | (1022 << 0) }; - outputPitch >>= 2, inputPitch >>= 2; - - #pragma omp parallel for - for(unsigned y = 0; y < height; y++) { - const uint32_t *in = input + y * inputPitch; - uint32_t *out0 = output + y * outputPitch * 2; - uint32_t *out1 = output + y * outputPitch * 2 + outputPitch; - - for(unsigned x = 0; x < width; x++) { - *out0++ = *in; - *out1++ = (*in++ & Mask) >> 1; - } - } -} diff --git a/snesfilter/nall/array.hpp b/snesfilter/nall/array.hpp deleted file mode 100755 index 4847a297..00000000 --- a/snesfilter/nall/array.hpp +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef NALL_ARRAY_HPP -#define NALL_ARRAY_HPP - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace nall { - //dynamic vector array - //neither constructor nor destructor is ever invoked; - //thus, this should only be used for POD objects. - template class array { - protected: - T *pool; - unsigned poolsize, buffersize; - - public: - unsigned size() const { return buffersize; } - unsigned capacity() const { return poolsize; } - - void reset() { - if(pool) free(pool); - pool = nullptr; - poolsize = 0; - buffersize = 0; - } - - void reserve(unsigned newsize) { - if(newsize == poolsize) return; - - pool = (T*)realloc(pool, newsize * sizeof(T)); - poolsize = newsize; - buffersize = min(buffersize, newsize); - } - - void resize(unsigned newsize) { - if(newsize > poolsize) reserve(bit::round(newsize)); //round reserve size up to power of 2 - buffersize = newsize; - } - - T* get(unsigned minsize = 0) { - if(minsize > buffersize) resize(minsize); - if(minsize > buffersize) throw "array[] out of bounds"; - return pool; - } - - void append(const T data) { - operator[](buffersize) = data; - } - - void append(const T data[], unsigned length) { - for(unsigned n = 0; n < length; n++) operator[](buffersize) = data[n]; - } - - void remove() { - if(size > 0) resize(size - 1); //remove last element only - } - - void remove(unsigned index, unsigned count = 1) { - for(unsigned i = index; count + i < buffersize; i++) { - pool[i] = pool[count + i]; - } - if(count + index >= buffersize) resize(index); //every element >= index was removed - else resize(buffersize - count); - } - - optional find(const T data) { - for(unsigned i = 0; i < size(); i++) if(pool[i] == data) return { true, i }; - return { false, 0 }; - } - - void clear() { - memset(pool, 0, buffersize * sizeof(T)); - } - - array() : pool(nullptr), poolsize(0), buffersize(0) { - } - - array(std::initializer_list list) : pool(nullptr), poolsize(0), buffersize(0) { - for(const T *p = list.begin(); p != list.end(); ++p) append(*p); - } - - ~array() { - reset(); - } - - //copy - array& operator=(const array &source) { - if(pool) free(pool); - buffersize = source.buffersize; - poolsize = source.poolsize; - pool = (T*)malloc(sizeof(T) * poolsize); //allocate entire pool size, - memcpy(pool, source.pool, sizeof(T) * buffersize); //... but only copy used pool objects - return *this; - } - - array(const array &source) : pool(nullptr), poolsize(0), buffersize(0) { - operator=(source); - } - - //move - array& operator=(array &&source) { - if(pool) free(pool); - pool = source.pool; - poolsize = source.poolsize; - buffersize = source.buffersize; - source.pool = nullptr; - source.reset(); - return *this; - } - - array(array &&source) : pool(nullptr), poolsize(0), buffersize(0) { - operator=(std::move(source)); - } - - //index - inline T& operator[](unsigned index) { - if(index >= buffersize) resize(index + 1); - if(index >= buffersize) throw "array[] out of bounds"; - return pool[index]; - } - - inline const T& operator[](unsigned index) const { - if(index >= buffersize) throw "array[] out of bounds"; - return pool[index]; - } - - //iteration - T* begin() { return &pool[0]; } - T* end() { return &pool[buffersize]; } - const T* begin() const { return &pool[0]; } - const T* end() const { return &pool[buffersize]; } - }; -} - -#endif diff --git a/snesfilter/nall/bit.hpp b/snesfilter/nall/bit.hpp deleted file mode 100755 index 67a35ad6..00000000 --- a/snesfilter/nall/bit.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef NALL_BIT_HPP -#define NALL_BIT_HPP - -namespace nall { - template constexpr inline unsigned uclamp(const unsigned x) { - enum { y = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) }; - return y + ((x - y) & -(x < y)); //min(x, y); - } - - template constexpr inline unsigned uclip(const unsigned x) { - enum { m = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) }; - return (x & m); - } - - template constexpr inline signed sclamp(const signed x) { - enum { b = 1U << (bits - 1), m = (1U << (bits - 1)) - 1 }; - return (x > m) ? m : (x < -b) ? -b : x; - } - - template constexpr inline signed sclip(const signed x) { - enum { b = 1U << (bits - 1), m = (1U << bits) - 1 }; - return ((x & m) ^ b) - b; - } - - namespace bit { - //lowest(0b1110) == 0b0010 - template constexpr inline T lowest(const T x) { - return x & -x; - } - - //clear_lowest(0b1110) == 0b1100 - template constexpr inline T clear_lowest(const T x) { - return x & (x - 1); - } - - //set_lowest(0b0101) == 0b0111 - template constexpr inline T set_lowest(const T x) { - return x | (x + 1); - } - - //round up to next highest single bit: - //round(15) == 16, round(16) == 16, round(17) == 32 - inline unsigned round(unsigned x) { - if((x & (x - 1)) == 0) return x; - while(x & (x - 1)) x &= x - 1; - return x << 1; - } - } -} - -#endif diff --git a/snesfilter/nall/moduloarray.hpp b/snesfilter/nall/moduloarray.hpp deleted file mode 100755 index be549ae9..00000000 --- a/snesfilter/nall/moduloarray.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef NALL_MODULO_HPP -#define NALL_MODULO_HPP - -#include - -namespace nall { - template class modulo_array { - public: - inline T operator[](int index) const { - return buffer[size + index]; - } - - inline T read(int index) const { - return buffer[size + index]; - } - - inline void write(unsigned index, const T value) { - buffer[index] = - buffer[index + size] = - buffer[index + size + size] = value; - } - - void serialize(serializer &s) { - s.array(buffer, size * 3); - } - - modulo_array() { - buffer = new T[size * 3](); - } - - ~modulo_array() { - delete[] buffer; - } - - private: - T *buffer; - }; -} - -#endif diff --git a/snesfilter/nall/platform.hpp b/snesfilter/nall/platform.hpp deleted file mode 100755 index f3e4b3f5..00000000 --- a/snesfilter/nall/platform.hpp +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef NALL_PLATFORM_HPP -#define NALL_PLATFORM_HPP - -#if defined(_WIN32) - //minimum version needed for _wstat64, etc - #undef __MSVCRT_VERSION__ - #define __MSVCRT_VERSION__ 0x0601 - #include -#endif - -//========================= -//standard platform headers -//========================= - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#if defined(_WIN32) - #include - #include - #include - #include - #undef interface - #define dllexport __declspec(dllexport) -#else - #include - #include - #define dllexport -#endif - -//================== -//warning supression -//================== - -//Visual C++ -#if defined(_MSC_VER) - //disable libc "deprecation" warnings - #pragma warning(disable:4996) -#endif - -//================ -//POSIX compliance -//================ - -#if defined(_MSC_VER) - #define PATH_MAX _MAX_PATH - #define va_copy(dest, src) ((dest) = (src)) -#endif - -#if defined(_WIN32) - #define getcwd _getcwd - #define ftruncate _chsize - #define mkdir(n, m) _wmkdir(nall::utf16_t(n)) - #define putenv _putenv - #define rmdir _rmdir - #define usleep(n) Sleep(n / 1000) - #define vsnprintf _vsnprintf -#endif - -//================ -//inline expansion -//================ - -#if defined(__GNUC__) - #define noinline __attribute__((noinline)) - #define inline inline - #define alwaysinline inline __attribute__((always_inline)) -#elif defined(_MSC_VER) - #define noinline __declspec(noinline) - #define inline inline - #define alwaysinline inline __forceinline -#else - #define noinline - #define inline inline - #define alwaysinline inline -#endif - -//========================= -//file system functionality -//========================= - -#if defined(_WIN32) - inline char* realpath(const char *filename, char *resolvedname) { - wchar_t fn[_MAX_PATH] = L""; - _wfullpath(fn, nall::utf16_t(filename), _MAX_PATH); - strcpy(resolvedname, nall::utf8_t(fn)); - for(unsigned n = 0; resolvedname[n]; n++) if(resolvedname[n] == '\\') resolvedname[n] = '/'; - return resolvedname; - } - - inline char* userpath(char *path) { - wchar_t fp[_MAX_PATH] = L""; - SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp); - strcpy(path, nall::utf8_t(fp)); - for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/'; - unsigned length = strlen(path); - if(path[length] != '/') strcpy(path + length, "/"); - return path; - } - - inline char* getcwd(char *path) { - wchar_t fp[_MAX_PATH] = L""; - _wgetcwd(fp, _MAX_PATH); - strcpy(path, nall::utf8_t(fp)); - for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/'; - unsigned length = strlen(path); - if(path[length] != '/') strcpy(path + length, "/"); - return path; - } -#else - //realpath() already exists - - inline char* userpath(char *path) { - *path = 0; - struct passwd *userinfo = getpwuid(getuid()); - if(userinfo) strcpy(path, userinfo->pw_dir); - unsigned length = strlen(path); - if(path[length] != '/') strcpy(path + length, "/"); - return path; - } - - inline char *getcwd(char *path) { - auto unused = getcwd(path, PATH_MAX); - unsigned length = strlen(path); - if(path[length] != '/') strcpy(path + length, "/"); - return path; - } -#endif - -#endif - diff --git a/snesfilter/nall/reference_array.hpp b/snesfilter/nall/reference_array.hpp deleted file mode 100755 index 7c915090..00000000 --- a/snesfilter/nall/reference_array.hpp +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef NALL_REFERENCE_ARRAY_HPP -#define NALL_REFERENCE_ARRAY_HPP - -#include -#include -#include - -namespace nall { - template struct reference_array { - struct exception_out_of_bounds{}; - - protected: - typedef typename std::remove_reference::type type_t; - type_t **pool; - unsigned poolsize, buffersize; - - public: - unsigned size() const { return buffersize; } - unsigned capacity() const { return poolsize; } - - void reset() { - if(pool) free(pool); - pool = nullptr; - poolsize = 0; - buffersize = 0; - } - - void reserve(unsigned newsize) { - if(newsize == poolsize) return; - - pool = (type_t**)realloc(pool, sizeof(type_t*) * newsize); - poolsize = newsize; - buffersize = min(buffersize, newsize); - } - - void resize(unsigned newsize) { - if(newsize > poolsize) reserve(bit::round(newsize)); - buffersize = newsize; - } - - template - bool append(type_t& data, Args&&... args) { - bool result = append(data); - append(std::forward(args)...); - return result; - } - - bool append(type_t& data) { - for(unsigned index = 0; index < buffersize; index++) { - if(pool[index] == &data) return false; - } - - unsigned index = buffersize++; - if(index >= poolsize) resize(index + 1); - pool[index] = &data; - return true; - } - - bool remove(type_t& data) { - for(unsigned index = 0; index < buffersize; index++) { - if(pool[index] == &data) { - for(unsigned i = index; i < buffersize - 1; i++) pool[i] = pool[i + 1]; - resize(buffersize - 1); - return true; - } - } - return false; - } - - template reference_array(Args&... args) : pool(nullptr), poolsize(0), buffersize(0) { - construct(args...); - } - - ~reference_array() { - reset(); - } - - reference_array& operator=(const reference_array &source) { - if(pool) free(pool); - buffersize = source.buffersize; - poolsize = source.poolsize; - pool = (type_t**)malloc(sizeof(type_t*) * poolsize); - memcpy(pool, source.pool, sizeof(type_t*) * buffersize); - return *this; - } - - reference_array& operator=(const reference_array &&source) { - if(pool) free(pool); - pool = source.pool; - poolsize = source.poolsize; - buffersize = source.buffersize; - source.pool = nullptr; - source.reset(); - return *this; - } - - inline type_t& operator[](unsigned index) { - if(index >= buffersize) throw exception_out_of_bounds(); - return *pool[index]; - } - - inline type_t& operator[](unsigned index) const { - if(index >= buffersize) throw exception_out_of_bounds(); - return *pool[index]; - } - - //iteration - struct iterator { - bool operator!=(const iterator &source) const { return index != source.index; } - type_t& operator*() { return array.operator[](index); } - iterator& operator++() { index++; return *this; } - iterator(const reference_array &array, unsigned index) : array(array), index(index) {} - private: - const reference_array &array; - unsigned index; - }; - - iterator begin() { return iterator(*this, 0); } - iterator end() { return iterator(*this, buffersize); } - const iterator begin() const { return iterator(*this, 0); } - const iterator end() const { return iterator(*this, buffersize); } - - private: - void construct() { - } - - void construct(const reference_array &source) { - operator=(source); - } - - void construct(const reference_array &&source) { - operator=(std::move(source)); - } - - template void construct(T data, Args&... args) { - append(data); - construct(args...); - } - }; -} - -#endif diff --git a/snesfilter/nall/resource.hpp b/snesfilter/nall/resource.hpp deleted file mode 100755 index f8fd5153..00000000 --- a/snesfilter/nall/resource.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef NALL_RESOURCE_HPP -#define NALL_RESOURCE_HPP - -#include -#include - -namespace nall { - -struct resource { - //create resource with "zip -9 resource.zip resource" - static bool encode(const char *outputFilename, const char *inputFilename) { - file fp; - if(fp.open(inputFilename, file::mode::read) == false) return false; - unsigned size = fp.size(); - uint8_t *data = new uint8_t[size]; - fp.read(data, size); - fp.close(); - - fp.open(outputFilename, file::mode::write); - fp.print("static const uint8_t data[", size, "] = {\n"); - uint8_t *p = data; - while(size) { - fp.print(" "); - for(unsigned n = 0; n < 32 && size; n++, size--) { - fp.print((unsigned)*p++, ","); - } - fp.print("\n"); - } - fp.print("};\n"); - fp.close(); - - delete[] data; - } - - uint8_t *data; - unsigned size; - - //extract first file from ZIP archive - bool decode(const uint8_t *cdata, unsigned csize) { - if(data) delete[] data; - - zip archive; - if(archive.open(cdata, csize) == false) return false; - if(archive.file.size() == 0) return false; - bool result = archive.extract(archive.file[0], data, size); - archive.close(); - - return result; - } - - resource() : data(0), size(0) { - } - - ~resource() { - if(data) delete[] data; - } -}; - -} - -#endif diff --git a/snesfilter/nall/snes/cartridge.hpp b/snesfilter/nall/snes/cartridge.hpp deleted file mode 100755 index cac3fb1a..00000000 --- a/snesfilter/nall/snes/cartridge.hpp +++ /dev/null @@ -1,792 +0,0 @@ -#ifndef NALL_SNES_CARTRIDGE_HPP -#define NALL_SNES_CARTRIDGE_HPP - -namespace nall { - -class SnesCartridge { -public: - string markup; - inline SnesCartridge(const uint8_t *data, unsigned size); - -//private: - inline void read_header(const uint8_t *data, unsigned size); - inline unsigned find_header(const uint8_t *data, unsigned size); - inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr); - inline unsigned gameboy_ram_size(const uint8_t *data, unsigned size); - inline bool gameboy_has_rtc(const uint8_t *data, unsigned size); - - enum HeaderField { - CartName = 0x00, - Mapper = 0x15, - RomType = 0x16, - RomSize = 0x17, - RamSize = 0x18, - CartRegion = 0x19, - Company = 0x1a, - Version = 0x1b, - Complement = 0x1c, //inverse checksum - Checksum = 0x1e, - ResetVector = 0x3c, - }; - - enum Mode { - ModeNormal, - ModeBsxSlotted, - ModeBsx, - ModeSufamiTurbo, - ModeSuperGameBoy, - }; - - enum Type { - TypeNormal, - TypeBsxSlotted, - TypeBsxBios, - TypeBsx, - TypeSufamiTurboBios, - TypeSufamiTurbo, - TypeSuperGameBoy1Bios, - TypeSuperGameBoy2Bios, - TypeGameBoy, - TypeUnknown, - }; - - enum Region { - NTSC, - PAL, - }; - - enum MemoryMapper { - LoROM, - HiROM, - ExLoROM, - ExHiROM, - SuperFXROM, - SA1ROM, - SPC7110ROM, - BSCLoROM, - BSCHiROM, - BSXROM, - STROM, - }; - - enum DSP1MemoryMapper { - DSP1Unmapped, - DSP1LoROM1MB, - DSP1LoROM2MB, - DSP1HiROM, - }; - - bool loaded; //is a base cartridge inserted? - unsigned crc32; //crc32 of all cartridges (base+slot(s)) - unsigned rom_size; - unsigned ram_size; - - Mode mode; - Type type; - Region region; - MemoryMapper mapper; - DSP1MemoryMapper dsp1_mapper; - - bool has_bsx_slot; - bool has_superfx; - bool has_sa1; - bool has_srtc; - bool has_sdd1; - bool has_spc7110; - bool has_spc7110rtc; - bool has_cx4; - bool has_dsp1; - bool has_dsp2; - bool has_dsp3; - bool has_dsp4; - bool has_obc1; - bool has_st010; - bool has_st011; - bool has_st018; -}; - -#define T "\t" - -SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) { - read_header(data, size); - - string xml; - markup = ""; - - if(type == TypeBsx) { - markup.append("cartridge"); - return; - } - - if(type == TypeSufamiTurbo) { - markup.append("cartridge"); - return; - } - - if(type == TypeGameBoy) { - markup.append("cartridge rtc=", gameboy_has_rtc(data, size), "\n"); - if(gameboy_ram_size(data, size) > 0) { - markup.append(T "ram size=0x", hex(gameboy_ram_size(data, size)), "\n"); - } - return; - } - - markup.append("cartridge region=", region == NTSC ? "NTSC\n" : "PAL\n"); - - if(type == TypeSuperGameBoy1Bios) { - markup.append(T "rom\n"); - markup.append(T T "map mode=linear address=00-7f:8000-ffff\n"); - markup.append(T T "map mode=linear address=80-ff:8000-ffff\n"); - markup.append(T "icd2 revision=1\n"); - markup.append(T T "map address=00-3f:6000-7fff\n"); - markup.append(T T "map address=80-bf:6000-7fff\n"); - } else if(type == TypeSuperGameBoy2Bios) { - markup.append(T "rom\n"); - markup.append(T T "map mode=linear address=00-7f:8000-ffff\n"); - markup.append(T T "map mode=linear address=80-ff:8000-ffff\n"); - markup.append(T "icd2 revision=1\n"); - markup.append(T T "map address=00-3f:6000-7fff\n"); - markup.append(T T "map address=80-bf:6000-7fff\n"); - } else if(has_cx4) { - markup.append(T "hitachidsp model=HG51B169 frequency=20000000 firmware=cx4.bin sha256=ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18\n"); - markup.append(T T "rom\n"); - markup.append(T T T "map mode=linear address=00-7f:8000-ffff\n"); - markup.append(T T T "map mode=linear address=80-ff:8000-ffff\n"); - markup.append(T T "mmio\n"); - markup.append(T T T "map address=00-3f:6000-7fff\n"); - markup.append(T T T "map address=80-bf:6000-7fff\n"); - } else if(has_spc7110) { - markup.append(T "rom\n"); - markup.append(T T "map mode=shadow address=00-0f:8000-ffff\n"); - markup.append(T T "map mode=shadow address=80-bf:8000-ffff\n"); - markup.append(T T "map mode=linear address=c0-cf:0000-ffff\n"); - - markup.append(T "spc7110\n"); - markup.append(T T "mcu\n"); - markup.append(T T T "map address=d0-ff:0000-ffff offset=0x100000 size=0x", hex(size - 0x100000), "\n"); - markup.append(T T "ram size=0x", hex(ram_size), "\n"); - markup.append(T T T "map mode=linear address=00:6000-7fff\n"); - markup.append(T T T "map mode=linear address=30:6000-7fff\n"); - markup.append(T T "mmio\n"); - markup.append(T T T "map address=00-3f:4800-483f\n"); - markup.append(T T T "map address=80-bf:4800-483f\n"); - if(has_spc7110rtc) { - markup.append(T T "rtc\n"); - markup.append(T T T "map address=00-3f:4840-4842\n"); - markup.append(T T T "map address=80-bf:4840-4842\n"); - } - markup.append(T T "dcu\n"); - markup.append(T T T "map address=50:0000-ffff\n"); - } else if(mapper == LoROM) { - markup.append(T "rom\n"); - markup.append(T T "map mode=linear address=00-7f:8000-ffff\n"); - markup.append(T T "map mode=linear address=80-ff:8000-ffff\n"); - - if(ram_size > 0) { - markup.append(T "ram size=0x", hex(ram_size), "\n"); - markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); - markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); - if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { - markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); - markup.append(T T "map mode=linear address=f0-ff:0000-7fff\n"); - } else { - markup.append(T T "map mode=linear address=70-7f:0000-ffff\n"); - markup.append(T T "map mode=linear address=f0-ff:0000-ffff\n"); - } - } - } else if(mapper == HiROM) { - markup.append(T "rom\n"); - markup.append(T T "map mode=shadow address=00-3f:8000-ffff\n"); - markup.append(T T "map mode=linear address=40-7f:0000-ffff\n"); - markup.append(T T "map mode=shadow address=80-bf:8000-ffff\n"); - markup.append(T T "map mode=linear address=c0-ff:0000-ffff\n"); - - if(ram_size > 0) { - markup.append(T "ram size=0x", hex(ram_size), "\n"); - markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); - markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); - if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { - markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); - } else { - markup.append(T T "map mode=linear address=70-7f:0000-ffff\n"); - } - } - } else if(mapper == ExLoROM) { - markup.append(T "rom\n"); - markup.append(T T "map mode=linear address=00-3f:8000-ffff\n"); - markup.append(T T "map mode=linear address=40-7f:0000-ffff\n"); - markup.append(T T "map mode=linear address=80-bf:8000-ffff\n"); - - if(ram_size > 0) { - markup.append(T "ram size=0x", hex(ram_size), "\n"); - markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); - markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); - markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); - } - } else if(mapper == ExHiROM) { - markup.append(T "rom\n"); - markup.append(T T "map mode=shadow address=00-3f:8000-ffff offset=0x400000\n"); - markup.append(T T "map mode=linear address=40-7f:0000-ffff offset=0x400000\n"); - markup.append(T T "map mode=shadow address=80-bf:8000-ffff offset=0x000000\n"); - markup.append(T T "map mode=linear address=c0-ff:0000-ffff offset=0x000000\n"); - - if(ram_size > 0) { - markup.append(T "ram size=0x", hex(ram_size), "\n"); - markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); - markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); - if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { - markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); - } else { - markup.append(T T "map mode=linear address=70-7f:0000-ffff\n"); - } - } - } else if(mapper == SuperFXROM) { - markup.append(T "superfx revision=2\n"); - markup.append(T T "rom\n"); - markup.append(T T T "map mode=linear address=00-3f:8000-ffff\n"); - markup.append(T T T "map mode=linear address=40-5f:0000-ffff\n"); - markup.append(T T T "map mode=linear address=80-bf:8000-ffff\n"); - markup.append(T T T "map mode=linear address=c0-df:0000-ffff\n"); - markup.append(T T "ram size=0x", hex(ram_size), "\n"); - markup.append(T T T "map mode=linear address=00-3f:6000-7fff size=0x2000\n"); - markup.append(T T T "map mode=linear address=60-7f:0000-ffff\n"); - markup.append(T T T "map mode=linear address=80-bf:6000-7fff size=0x2000\n"); - markup.append(T T T "map mode=linear address=e0-ff:0000-ffff\n"); - markup.append(T T "mmio\n"); - markup.append(T T T "map address=00-3f:3000-32ff\n"); - markup.append(T T T "map address=80-bf:3000-32ff\n"); - } else if(mapper == SA1ROM) { - markup.append(T "sa1\n"); - markup.append(T T "mcu\n"); - markup.append(T T T "rom\n"); - markup.append(T T T T "map mode=direct address=00-3f:8000-ffff\n"); - markup.append(T T T T "map mode=direct address=80-bf:8000-ffff\n"); - markup.append(T T T T "map mode=direct address=c0-ff:0000-ffff\n"); - markup.append(T T T "ram\n"); - markup.append(T T T T "map mode=direct address=00-3f:6000-7fff\n"); - markup.append(T T T T "map mode=direct address=80-bf:6000-7fff\n"); - markup.append(T T "iram size=0x800\n"); - markup.append(T T T "map mode=linear address=00-3f:3000-37ff\n"); - markup.append(T T T "map mode=linear address=80-bf:3000-37ff\n"); - markup.append(T T "bwram size=0x", hex(ram_size), "\n"); - markup.append(T T T "map mode=linear address=40-4f:0000-ffff\n"); - markup.append(T T "mmio\n"); - markup.append(T T T "map address=00-3f:2200-23ff\n"); - markup.append(T T T "map address=80-bf:2200-23ff\n"); - } else if(mapper == BSCLoROM) { - markup.append(T "rom\n"); - markup.append(T T "map mode=linear address=00-1f:8000-ffff offset=0x000000\n"); - markup.append(T T "map mode=linear address=20-3f:8000-ffff offset=0x100000\n"); - markup.append(T T "map mode=linear address=80-9f:8000-ffff offset=0x200000\n"); - markup.append(T T "map mode=linear address=a0-bf:8000-ffff offset=0x100000\n"); - markup.append(T "ram size=0x", hex(ram_size), "\n"); - markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); - markup.append(T T "map mode=linear address=f0-ff:0000-7fff\n"); - markup.append(T "bsx\n"); - markup.append(T T "slot\n"); - markup.append(T T T "map mode=linear address=c0-ef:0000-ffff\n"); - } else if(mapper == BSCHiROM) { - markup.append(T "rom\n"); - markup.append(T T "map mode=shadow address=00-1f:8000-ffff\n"); - markup.append(T T "map mode=linear address=40-5f:0000-ffff\n"); - markup.append(T T "map mode=shadow address=80-9f:8000-ffff\n"); - markup.append(T T "map mode=linear address=c0-df:0000-ffff\n"); - markup.append(T "ram size=0x", hex(ram_size), "\n"); - markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); - markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); - markup.append(T "bsx\n"); - markup.append(T T "slot\n"); - markup.append(T T T "map mode=shadow address=20-3f:8000-ffff\n"); - markup.append(T T T "map mode=linear address=60-7f:0000-ffff\n"); - markup.append(T T T "map mode=shadow address=a0-bf:8000-ffff\n"); - markup.append(T T T "map mode=linear address=e0-ff:0000-ffff\n"); - } else if(mapper == BSXROM) { - markup.append(T "bsx\n"); - markup.append(T T "mcu\n"); - markup.append(T T T "map address=00-3f:8000-ffff\n"); - markup.append(T T T "map address=80-bf:8000-ffff\n"); - markup.append(T T T "map address=40-7f:0000-ffff\n"); - markup.append(T T T "map address=c0-ff:0000-ffff\n"); - markup.append(T T T "map address=20-3f:6000-7fff\n"); - markup.append(T T "mmio\n"); - markup.append(T T T "map address=00-3f:5000-5fff\n"); - markup.append(T T T "map address=80-bf:5000-5fff\n"); - } else if(mapper == STROM) { - markup.append(T "rom\n"); - markup.append(T T "map mode=linear address=00-1f:8000-ffff\n"); - markup.append(T T "map mode=linear address=80-9f:8000-ffff\n"); - markup.append(T "sufamiturbo\n"); - markup.append(T T "slot id=A\n"); - markup.append(T T T "rom\n"); - markup.append(T T T T "map mode=linear address=20-3f:8000-ffff\n"); - markup.append(T T T T "map mode=linear address=a0-bf:8000-ffff\n"); - markup.append(T T T "ram size=0x20000\n"); - markup.append(T T T T "map mode=linear address=60-63:8000-ffff\n"); - markup.append(T T T T "map mode=linear address=e0-e3:8000-ffff\n"); - markup.append(T T "slot id=B\n"); - markup.append(T T T "rom\n"); - markup.append(T T T T "map mode=linear address=40-5f:8000-ffff\n"); - markup.append(T T T T "map mode=linear address=c0-df:8000-ffff\n"); - markup.append(T T T "ram size=0x20000\n"); - markup.append(T T T T "map mode=linear address=70-73:8000-ffff\n"); - markup.append(T T T T "map mode=linear address=f0-f3:8000-ffff\n"); - } - - if(has_srtc) { - markup.append(T "srtc\n"); - markup.append(T T "map address=00-3f:2800-2801\n"); - markup.append(T T "map address=80-bf:2800-2801\n"); - } - - if(has_sdd1) { - markup.append(T "sdd1\n"); - markup.append(T T "mcu\n"); - markup.append(T T T "map address=c0-ff:0000-ffff\n"); - markup.append(T T "mmio\n"); - markup.append(T T T "map address=00-3f:4800-4807\n"); - markup.append(T T T "map address=80-bf:4800-4807\n"); - } - - if(has_dsp1) { - markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp1b.bin sha256=4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c\n"); - if(dsp1_mapper == DSP1LoROM1MB) { - markup.append(T T "dr\n"); - markup.append(T T T "map address=20-3f:8000-bfff\n"); - markup.append(T T T "map address=a0-bf:8000-bfff\n"); - markup.append(T T "sr\n"); - markup.append(T T T "map address=20-3f:c000-ffff\n"); - markup.append(T T T "map address=a0-bf:c000-ffff\n"); - } else if(dsp1_mapper == DSP1LoROM2MB) { - markup.append(T T "dr\n"); - markup.append(T T T "map address=60-6f:0000-3fff\n"); - markup.append(T T T "map address=e0-ef:0000-3fff\n"); - markup.append(T T "sr\n"); - markup.append(T T T "map address=60-6f:4000-7fff\n"); - markup.append(T T T "map address=e0-ef:4000-7fff\n"); - } else if(dsp1_mapper == DSP1HiROM) { - markup.append(T T "dr\n"); - markup.append(T T T "map address=00-1f:6000-6fff\n"); - markup.append(T T T "map address=80-9f:6000-6fff\n"); - markup.append(T T "sr\n"); - markup.append(T T T "map address=00-1f:7000-7fff\n"); - markup.append(T T T "map address=80-9f:7000-7fff\n"); - } - } - - if(has_dsp2) { - markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp2.bin sha256=5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1\n"); - markup.append(T T "dr\n"); - markup.append(T T T "map address=20-3f:8000-bfff\n"); - markup.append(T T T "map address=a0-bf:8000-bfff\n"); - markup.append(T T "sr\n"); - markup.append(T T T "map address=20-3f:c000-ffff\n"); - markup.append(T T T "map address=a0-bf:c000-ffff\n"); - } - - if(has_dsp3) { - markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp3.bin sha256=2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90\n"); - markup.append(T T "dr\n"); - markup.append(T T T "map address=20-3f:8000-bfff\n"); - markup.append(T T T "map address=a0-bf:8000-bfff\n"); - markup.append(T T "sr\n"); - markup.append(T T T "map address=20-3f:c000-ffff\n"); - markup.append(T T T "map address=a0-bf:c000-ffff\n"); - } - - if(has_dsp4) { - markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp4.bin sha256=63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a\n"); - markup.append(T T "dr\n"); - markup.append(T T T "map address=30-3f:8000-bfff\n"); - markup.append(T T T "map address=b0-bf:8000-bfff\n"); - markup.append(T T "sr\n"); - markup.append(T T T "map address=30-3f:c000-ffff\n"); - markup.append(T T T "map address=b0-bf:c000-ffff\n"); - } - - if(has_obc1) { - markup.append(T "obc1\n"); - markup.append(T T "map address=00-3f:6000-7fff\n"); - markup.append(T T "map address=80-bf:6000-7fff\n"); - } - - if(has_st010) { - markup.append(T "necdsp model=uPD96050 frequency=10000000 firmware=st0010.bin sha256=55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e\n"); - markup.append(T T "dr\n"); - markup.append(T T T "map address=60:0000\n"); - markup.append(T T T "map address=e0:0000\n"); - markup.append(T T "sr\n"); - markup.append(T T T "map address=60:0001\n"); - markup.append(T T T "map address=e0:0001\n"); - markup.append(T T "dp\n"); - markup.append(T T T "map address=68-6f:0000-0fff\n"); - markup.append(T T T "map address=e8-ef:0000-0fff\n"); - } - - if(has_st011) { - markup.append(T "necdsp model=uPD96050 frequency=15000000 firmware=st0011.bin sha256=651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e\n"); - markup.append(T T "dr\n"); - markup.append(T T T "map address=60:0000\n"); - markup.append(T T T "map address=e0:0000\n"); - markup.append(T T "sr\n"); - markup.append(T T T "map address=60:0001\n"); - markup.append(T T T "map address=e0:0001\n"); - markup.append(T T "dp\n"); - markup.append(T T T "map address=68-6f:0000-0fff\n"); - markup.append(T T T "map address=e8-ef:0000-0fff\n"); - } - - if(has_st018) { - markup.append(T "setarisc firmware=ST-0018\n"); - markup.append(T T "map address=00-3f:3800-38ff\n"); - markup.append(T T "map address=80-bf:3800-38ff\n"); - } -} - -#undef T - -void SnesCartridge::read_header(const uint8_t *data, unsigned size) { - type = TypeUnknown; - mapper = LoROM; - dsp1_mapper = DSP1Unmapped; - region = NTSC; - rom_size = size; - ram_size = 0; - - has_bsx_slot = false; - has_superfx = false; - has_sa1 = false; - has_srtc = false; - has_sdd1 = false; - has_spc7110 = false; - has_spc7110rtc = false; - has_cx4 = false; - has_dsp1 = false; - has_dsp2 = false; - has_dsp3 = false; - has_dsp4 = false; - has_obc1 = false; - has_st010 = false; - has_st011 = false; - has_st018 = false; - - //===================== - //detect Game Boy carts - //===================== - - if(size >= 0x0140) { - if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66 - && data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) { - type = TypeGameBoy; - return; - } - } - - if(size < 32768) { - type = TypeUnknown; - return; - } - - const unsigned index = find_header(data, size); - const uint8_t mapperid = data[index + Mapper]; - const uint8_t rom_type = data[index + RomType]; - const uint8_t rom_size = data[index + RomSize]; - const uint8_t company = data[index + Company]; - const uint8_t regionid = data[index + CartRegion] & 0x7f; - - ram_size = 1024 << (data[index + RamSize] & 7); - if(ram_size == 1024) ram_size = 0; //no RAM present - - //0, 1, 13 = NTSC; 2 - 12 = PAL - region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL; - - //======================= - //detect BS-X flash carts - //======================= - - if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) { - if(data[index + 0x14] == 0x00) { - const uint8_t n15 = data[index + 0x15]; - if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) { - if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) { - type = TypeBsx; - mapper = BSXROM; - region = NTSC; //BS-X only released in Japan - return; - } - } - } - } - - //========================= - //detect Sufami Turbo carts - //========================= - - if(!memcmp(data, "BANDAI SFC-ADX", 14)) { - if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) { - type = TypeSufamiTurboBios; - } else { - type = TypeSufamiTurbo; - } - mapper = STROM; - region = NTSC; //Sufami Turbo only released in Japan - return; //RAM size handled outside this routine - } - - //========================== - //detect Super Game Boy BIOS - //========================== - - if(!memcmp(data + index, "Super GAMEBOY2", 14)) { - type = TypeSuperGameBoy2Bios; - return; - } - - if(!memcmp(data + index, "Super GAMEBOY", 13)) { - type = TypeSuperGameBoy1Bios; - return; - } - - //===================== - //detect standard carts - //===================== - - //detect presence of BS-X flash cartridge connector (reads extended header information) - if(data[index - 14] == 'Z') { - if(data[index - 11] == 'J') { - uint8_t n13 = data[index - 13]; - if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) { - if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) { - has_bsx_slot = true; - } - } - } - } - - if(has_bsx_slot) { - if(!memcmp(data + index, "Satellaview BS-X ", 21)) { - //BS-X base cart - type = TypeBsxBios; - mapper = BSXROM; - region = NTSC; //BS-X only released in Japan - return; //RAM size handled internally by load_cart_bsx() -> BSXCart class - } else { - type = TypeBsxSlotted; - mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM); - region = NTSC; //BS-X slotted cartridges only released in Japan - } - } else { - //standard cart - type = TypeNormal; - - if(index == 0x7fc0 && size >= 0x401000) { - mapper = ExLoROM; - } else if(index == 0x7fc0 && mapperid == 0x32) { - mapper = ExLoROM; - } else if(index == 0x7fc0) { - mapper = LoROM; - } else if(index == 0xffc0) { - mapper = HiROM; - } else { //index == 0x40ffc0 - mapper = ExHiROM; - } - } - - if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) { - has_superfx = true; - mapper = SuperFXROM; - ram_size = 1024 << (data[index - 3] & 7); - if(ram_size == 1024) ram_size = 0; - } - - if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) { - has_sa1 = true; - mapper = SA1ROM; - } - - if(mapperid == 0x35 && rom_type == 0x55) { - has_srtc = true; - } - - if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) { - has_sdd1 = true; - } - - if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) { - has_spc7110 = true; - has_spc7110rtc = (rom_type == 0xf9); - mapper = SPC7110ROM; - } - - if(mapperid == 0x20 && rom_type == 0xf3) { - has_cx4 = true; - } - - if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) { - has_dsp1 = true; - } - - if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) { - has_dsp1 = true; - } - - if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) { - has_dsp1 = true; - } - - if(has_dsp1 == true) { - if((mapperid & 0x2f) == 0x20 && size <= 0x100000) { - dsp1_mapper = DSP1LoROM1MB; - } else if((mapperid & 0x2f) == 0x20) { - dsp1_mapper = DSP1LoROM2MB; - } else if((mapperid & 0x2f) == 0x21) { - dsp1_mapper = DSP1HiROM; - } - } - - if(mapperid == 0x20 && rom_type == 0x05) { - has_dsp2 = true; - } - - if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) { - has_dsp3 = true; - } - - if(mapperid == 0x30 && rom_type == 0x03) { - has_dsp4 = true; - } - - if(mapperid == 0x30 && rom_type == 0x25) { - has_obc1 = true; - } - - if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) { - has_st010 = true; - } - - if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) { - has_st011 = true; - } - - if(mapperid == 0x30 && rom_type == 0xf5) { - has_st018 = true; - } -} - -unsigned SnesCartridge::find_header(const uint8_t *data, unsigned size) { - unsigned score_lo = score_header(data, size, 0x007fc0); - unsigned score_hi = score_header(data, size, 0x00ffc0); - unsigned score_ex = score_header(data, size, 0x40ffc0); - if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits - - if(score_lo >= score_hi && score_lo >= score_ex) { - return 0x007fc0; - } else if(score_hi >= score_ex) { - return 0x00ffc0; - } else { - return 0x40ffc0; - } -} - -unsigned SnesCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) { - if(size < addr + 64) return 0; //image too small to contain header at this location? - int score = 0; - - uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8); - uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8); - uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8); - - uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset - uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit - - //$00:[000-7fff] contains uninitialized RAM and MMIO. - //reset vector must point to ROM at $00:[8000-ffff] to be considered valid. - if(resetvector < 0x8000) return 0; - - //some images duplicate the header in multiple locations, and others have completely - //invalid header information that cannot be relied upon. - //below code will analyze the first opcode executed at the specified reset vector to - //determine the probability that this is the correct header. - - //most likely opcodes - if(resetop == 0x78 //sei - || resetop == 0x18 //clc (clc; xce) - || resetop == 0x38 //sec (sec; xce) - || resetop == 0x9c //stz $nnnn (stz $4200) - || resetop == 0x4c //jmp $nnnn - || resetop == 0x5c //jml $nnnnnn - ) score += 8; - - //plausible opcodes - if(resetop == 0xc2 //rep #$nn - || resetop == 0xe2 //sep #$nn - || resetop == 0xad //lda $nnnn - || resetop == 0xae //ldx $nnnn - || resetop == 0xac //ldy $nnnn - || resetop == 0xaf //lda $nnnnnn - || resetop == 0xa9 //lda #$nn - || resetop == 0xa2 //ldx #$nn - || resetop == 0xa0 //ldy #$nn - || resetop == 0x20 //jsr $nnnn - || resetop == 0x22 //jsl $nnnnnn - ) score += 4; - - //implausible opcodes - if(resetop == 0x40 //rti - || resetop == 0x60 //rts - || resetop == 0x6b //rtl - || resetop == 0xcd //cmp $nnnn - || resetop == 0xec //cpx $nnnn - || resetop == 0xcc //cpy $nnnn - ) score -= 4; - - //least likely opcodes - if(resetop == 0x00 //brk #$nn - || resetop == 0x02 //cop #$nn - || resetop == 0xdb //stp - || resetop == 0x42 //wdm - || resetop == 0xff //sbc $nnnnnn,x - ) score -= 8; - - //at times, both the header and reset vector's first opcode will match ... - //fallback and rely on info validity in these cases to determine more likely header. - - //a valid checksum is the biggest indicator of a valid header. - if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4; - - if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM - if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM - if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually ExLoROM - if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM - - if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header - if(data[addr + RomType] < 0x08) score++; - if(data[addr + RomSize] < 0x10) score++; - if(data[addr + RamSize] < 0x08) score++; - if(data[addr + CartRegion] < 14) score++; - - if(score < 0) score = 0; - return score; -} - -unsigned SnesCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) { - if(size < 512) return 0; - switch(data[0x0149]) { - case 0x00: return 0 * 1024; - case 0x01: return 8 * 1024; - case 0x02: return 8 * 1024; - case 0x03: return 32 * 1024; - case 0x04: return 128 * 1024; - case 0x05: return 128 * 1024; - default: return 128 * 1024; - } -} - -bool SnesCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) { - if(size < 512) return false; - if(data[0x0147] == 0x0f ||data[0x0147] == 0x10) return true; - return false; -} - -} - -#endif diff --git a/snesfilter/nall/snes/cpu.hpp b/snesfilter/nall/snes/cpu.hpp deleted file mode 100755 index 28f5ddb5..00000000 --- a/snesfilter/nall/snes/cpu.hpp +++ /dev/null @@ -1,458 +0,0 @@ -#ifndef NALL_SNES_CPU_HPP -#define NALL_SNES_CPU_HPP - -namespace nall { - -struct SNESCPU { - enum : unsigned { - Implied, // - Constant, //#$00 - AccumConstant, //#$00 - IndexConstant, //#$00 - Direct, //$00 - DirectX, //$00,x - DirectY, //$00,y - IDirect, //($00) - IDirectX, //($00,x) - IDirectY, //($00),y - ILDirect, //[$00] - ILDirectY, //[$00],y - Address, //$0000 - AddressX, //$0000,x - AddressY, //$0000,y - IAddressX, //($0000,x) - ILAddress, //[$0000] - PAddress, //PBR:$0000 - PIAddress, //PBR:($0000) - Long, //$000000 - LongX, //$000000,x - Stack, //$00,s - IStackY, //($00,s),y - BlockMove, //$00,$00 - RelativeShort, //+/- $00 - RelativeLong, //+/- $0000 - }; - - struct OpcodeInfo { - char name[4]; - unsigned mode; - }; - - static const OpcodeInfo opcodeInfo[256]; - - static unsigned getOpcodeLength(bool accum, bool index, uint8_t opcode); - static string disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb); -}; - -const SNESCPU::OpcodeInfo SNESCPU::opcodeInfo[256] = { - //0x00 - 0x0f - { "brk", Constant }, - { "ora", IDirectX }, - { "cop", Constant }, - { "ora", Stack }, - - { "tsb", Direct }, - { "ora", Direct }, - { "asl", Direct }, - { "ora", ILDirect }, - - { "php", Implied }, - { "ora", AccumConstant }, - { "asl", Implied }, - { "phd", Implied }, - - { "tsb", Address }, - { "ora", Address }, - { "asl", Address }, - { "ora", Long }, - - //0x10 - 0x1f - { "bpl", RelativeShort }, - { "ora", IDirectY }, - { "ora", IDirect }, - { "ora", IStackY }, - - { "trb", Direct }, - { "ora", DirectX }, - { "asl", DirectX }, - { "ora", ILDirectY }, - - { "clc", Implied }, - { "ora", AddressY }, - { "inc", Implied }, - { "tcs", Implied }, - - { "trb", Address }, - { "ora", AddressX }, - { "asl", AddressX }, - { "ora", LongX }, - - //0x20 - 0x2f - { "jsr", Address }, - { "and", IDirectX }, - { "jsl", Long }, - { "and", Stack }, - - { "bit", Direct }, - { "and", Direct }, - { "rol", Direct }, - { "and", ILDirect }, - - { "plp", Implied }, - { "and", AccumConstant }, - { "rol", Implied }, - { "pld", Implied }, - - { "bit", Address }, - { "and", Address }, - { "rol", Address }, - { "and", Long }, - - //0x30 - 0x3f - { "bmi", RelativeShort }, - { "and", IDirectY }, - { "and", IDirect }, - { "and", IStackY }, - - { "bit", DirectX }, - { "and", DirectX }, - { "rol", DirectX }, - { "and", ILDirectY }, - - { "sec", Implied }, - { "and", AddressY }, - { "dec", Implied }, - { "tsc", Implied }, - - { "bit", AddressX }, - { "and", AddressX }, - { "rol", AddressX }, - { "and", LongX }, - - //0x40 - 0x4f - { "rti", Implied }, - { "eor", IDirectX }, - { "wdm", Constant }, - { "eor", Stack }, - - { "mvp", BlockMove }, - { "eor", Direct }, - { "lsr", Direct }, - { "eor", ILDirect }, - - { "pha", Implied }, - { "eor", AccumConstant }, - { "lsr", Implied }, - { "phk", Implied }, - - { "jmp", PAddress }, - { "eor", Address }, - { "lsr", Address }, - { "eor", Long }, - - //0x50 - 0x5f - { "bvc", RelativeShort }, - { "eor", IDirectY }, - { "eor", IDirect }, - { "eor", IStackY }, - - { "mvn", BlockMove }, - { "eor", DirectX }, - { "lsr", DirectX }, - { "eor", ILDirectY }, - - { "cli", Implied }, - { "eor", AddressY }, - { "phy", Implied }, - { "tcd", Implied }, - - { "jml", Long }, - { "eor", AddressX }, - { "lsr", AddressX }, - { "eor", LongX }, - - //0x60 - 0x6f - { "rts", Implied }, - { "adc", IDirectX }, - { "per", Address }, - { "adc", Stack }, - - { "stz", Direct }, - { "adc", Direct }, - { "ror", Direct }, - { "adc", ILDirect }, - - { "pla", Implied }, - { "adc", AccumConstant }, - { "ror", Implied }, - { "rtl", Implied }, - - { "jmp", PIAddress }, - { "adc", Address }, - { "ror", Address }, - { "adc", Long }, - - //0x70 - 0x7f - { "bvs", RelativeShort }, - { "adc", IDirectY }, - { "adc", IDirect }, - { "adc", IStackY }, - - { "stz", DirectX }, - { "adc", DirectX }, - { "ror", DirectX }, - { "adc", ILDirectY }, - - { "sei", Implied }, - { "adc", AddressY }, - { "ply", Implied }, - { "tdc", Implied }, - - { "jmp", IAddressX }, - { "adc", AddressX }, - { "ror", AddressX }, - { "adc", LongX }, - - //0x80 - 0x8f - { "bra", RelativeShort }, - { "sta", IDirectX }, - { "brl", RelativeLong }, - { "sta", Stack }, - - { "sty", Direct }, - { "sta", Direct }, - { "stx", Direct }, - { "sta", ILDirect }, - - { "dey", Implied }, - { "bit", AccumConstant }, - { "txa", Implied }, - { "phb", Implied }, - - { "sty", Address }, - { "sta", Address }, - { "stx", Address }, - { "sta", Long }, - - //0x90 - 0x9f - { "bcc", RelativeShort }, - { "sta", IDirectY }, - { "sta", IDirect }, - { "sta", IStackY }, - - { "sty", DirectX }, - { "sta", DirectX }, - { "stx", DirectY }, - { "sta", ILDirectY }, - - { "tya", Implied }, - { "sta", AddressY }, - { "txs", Implied }, - { "txy", Implied }, - - { "stz", Address }, - { "sta", AddressX }, - { "stz", AddressX }, - { "sta", LongX }, - - //0xa0 - 0xaf - { "ldy", IndexConstant }, - { "lda", IDirectX }, - { "ldx", IndexConstant }, - { "lda", Stack }, - - { "ldy", Direct }, - { "lda", Direct }, - { "ldx", Direct }, - { "lda", ILDirect }, - - { "tay", Implied }, - { "lda", AccumConstant }, - { "tax", Implied }, - { "plb", Implied }, - - { "ldy", Address }, - { "lda", Address }, - { "ldx", Address }, - { "lda", Long }, - - //0xb0 - 0xbf - { "bcs", RelativeShort }, - { "lda", IDirectY }, - { "lda", IDirect }, - { "lda", IStackY }, - - { "ldy", DirectX }, - { "lda", DirectX }, - { "ldx", DirectY }, - { "lda", ILDirectY }, - - { "clv", Implied }, - { "lda", AddressY }, - { "tsx", Implied }, - { "tyx", Implied }, - - { "ldy", AddressX }, - { "lda", AddressX }, - { "ldx", AddressY }, - { "lda", LongX }, - - //0xc0 - 0xcf - { "cpy", IndexConstant }, - { "cmp", IDirectX }, - { "rep", Constant }, - { "cmp", Stack }, - - { "cpy", Direct }, - { "cmp", Direct }, - { "dec", Direct }, - { "cmp", ILDirect }, - - { "iny", Implied }, - { "cmp", AccumConstant }, - { "dex", Implied }, - { "wai", Implied }, - - { "cpy", Address }, - { "cmp", Address }, - { "dec", Address }, - { "cmp", Long }, - - //0xd0 - 0xdf - { "bne", RelativeShort }, - { "cmp", IDirectY }, - { "cmp", IDirect }, - { "cmp", IStackY }, - - { "pei", IDirect }, - { "cmp", DirectX }, - { "dec", DirectX }, - { "cmp", ILDirectY }, - - { "cld", Implied }, - { "cmp", AddressY }, - { "phx", Implied }, - { "stp", Implied }, - - { "jmp", ILAddress }, - { "cmp", AddressX }, - { "dec", AddressX }, - { "cmp", LongX }, - - //0xe0 - 0xef - { "cpx", IndexConstant }, - { "sbc", IDirectX }, - { "sep", Constant }, - { "sbc", Stack }, - - { "cpx", Direct }, - { "sbc", Direct }, - { "inc", Direct }, - { "sbc", ILDirect }, - - { "inx", Implied }, - { "sbc", AccumConstant }, - { "nop", Implied }, - { "xba", Implied }, - - { "cpx", Address }, - { "sbc", Address }, - { "inc", Address }, - { "sbc", Long }, - - //0xf0 - 0xff - { "beq", RelativeShort }, - { "sbc", IDirectY }, - { "sbc", IDirect }, - { "sbc", IStackY }, - - { "pea", Address }, - { "sbc", DirectX }, - { "inc", DirectX }, - { "sbc", ILDirectY }, - - { "sed", Implied }, - { "sbc", AddressY }, - { "plx", Implied }, - { "xce", Implied }, - - { "jsr", IAddressX }, - { "sbc", AddressX }, - { "inc", AddressX }, - { "sbc", LongX }, -}; - -inline unsigned SNESCPU::getOpcodeLength(bool accum, bool index, uint8_t opcode) { - switch(opcodeInfo[opcode].mode) { default: - case Implied: return 1; - case Constant: return 2; - case AccumConstant: return 3 - accum; - case IndexConstant: return 3 - index; - case Direct: return 2; - case DirectX: return 2; - case DirectY: return 2; - case IDirect: return 2; - case IDirectX: return 2; - case IDirectY: return 2; - case ILDirect: return 2; - case ILDirectY: return 2; - case Address: return 3; - case AddressX: return 3; - case AddressY: return 3; - case IAddressX: return 3; - case ILAddress: return 3; - case PAddress: return 3; - case PIAddress: return 3; - case Long: return 4; - case LongX: return 4; - case Stack: return 2; - case IStackY: return 2; - case BlockMove: return 3; - case RelativeShort: return 2; - case RelativeLong: return 3; - } -} - -inline string SNESCPU::disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb) { - string name = opcodeInfo[opcode].name; - unsigned mode = opcodeInfo[opcode].mode; - - if(mode == Implied) return name; - if(mode == Constant) return { name, " #$", hex<2>(pl) }; - if(mode == AccumConstant) return { name, " #$", accum ? "" : hex<2>(ph), hex<2>(pl) }; - if(mode == IndexConstant) return { name, " #$", index ? "" : hex<2>(ph), hex<2>(pl) }; - if(mode == Direct) return { name, " $", hex<2>(pl) }; - if(mode == DirectX) return { name, " $", hex<2>(pl), ",x" }; - if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" }; - if(mode == IDirect) return { name, " ($", hex<2>(pl), ")" }; - if(mode == IDirectX) return { name, " ($", hex<2>(pl), ",x)" }; - if(mode == IDirectY) return { name, " ($", hex<2>(pl), "),y" }; - if(mode == ILDirect) return { name, " [$", hex<2>(pl), "]" }; - if(mode == ILDirectY) return { name, " [$", hex<2>(pl), "],y" }; - if(mode == Address) return { name, " $", hex<2>(ph), hex<2>(pl) }; - if(mode == AddressX) return { name, " $", hex<2>(ph), hex<2>(pl), ",x" }; - if(mode == AddressY) return { name, " $", hex<2>(ph), hex<2>(pl), ",y" }; - if(mode == IAddressX) return { name, " ($", hex<2>(ph), hex<2>(pl), ",x)" }; - if(mode == ILAddress) return { name, " [$", hex<2>(ph), hex<2>(pl), "]" }; - if(mode == PAddress) return { name, " $", hex<2>(ph), hex<2>(pl) }; - if(mode == PIAddress) return { name, " ($", hex<2>(ph), hex<2>(pl), ")" }; - if(mode == Long) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl) }; - if(mode == LongX) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl), ",x" }; - if(mode == Stack) return { name, " $", hex<2>(pl), ",s" }; - if(mode == IStackY) return { name, " ($", hex<2>(pl), ",s),y" }; - if(mode == BlockMove) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) }; - if(mode == RelativeShort) { - unsigned addr = (pc + 2) + (int8_t)(pl << 0); - return { name, " $", hex<4>(addr) }; - } - if(mode == RelativeLong) { - unsigned addr = (pc + 3) + (int16_t)((ph << 8) + (pl << 0)); - return { name, " $", hex<4>(addr) }; - } - - return ""; -} - -} - -#endif diff --git a/snesfilter/nall/snes/smp.hpp b/snesfilter/nall/snes/smp.hpp deleted file mode 100755 index 7a1ac47b..00000000 --- a/snesfilter/nall/snes/smp.hpp +++ /dev/null @@ -1,639 +0,0 @@ -#ifndef NALL_SNES_SMP_HPP -#define NALL_SNES_SMP_HPP - -namespace nall { - -struct SNESSMP { - enum : unsigned { - Implied, // - TVector, //0 - Direct, //$00 - DirectRelative, //$00,+/-$00 - ADirect, //a,$00 - AAbsolute, //a,$0000 - AIX, //a,(x) - AIDirectX, //a,($00+x) - AConstant, //a,#$00 - DirectDirect, //$00,$00 - CAbsoluteBit, //c,$0000:0 - Absolute, //$0000 - P, //p - AbsoluteA, //$0000,a - Relative, //+/-$00 - ADirectX, //a,$00+x - AAbsoluteX, //a,$0000+x - AAbsoluteY, //a,$0000+y - AIDirectY, //a,($00)+y - DirectConstant, //$00,#$00 - IXIY, //(x),(y) - DirectX, //$00+x - A, //a - X, //x - XAbsolute, //x,$0000 - IAbsoluteX, //($0000+x) - CNAbsoluteBit, //c,!$0000:0 - XDirect, //x,$00 - PVector, //$ff00 - YaDirect, //ya,$00 - XA, //x,a - YAbsolute, //y,$0000 - Y, //y - AX, //a,x - YDirect, //y,$00 - YConstant, //y,#$00 - XSp, //x,sp - YaX, //ya,x - IXPA, //(x)+,a - SpX, //sp,x - AIXP, //a,(x)+ - DirectA, //$00,a - IXA, //(x),a - IDirectXA, //($00+x),a - XConstant, //x,#$00 - AbsoluteX, //$0000,x - AbsoluteBitC, //$0000:0,c - DirectY, //$00,y - AbsoluteY, //$0000,y - Ya, //ya - DirectXA, //$00+x,a - AbsoluteXA, //$0000+x,a - AbsoluteYA, //$0000+y,a - IDirectYA, //($00)+y,a - DirectYX, //$00+y,x - DirectYa, //$00,ya - DirectXY, //$00+x,y - AY, //a,y - DirectXRelative, //$00+x,+/-$00 - XDirectY, //x,$00+y - YDirectX, //y,$00+x - YA, //y,a - YRelative, //y,+/-$00 - }; - - struct OpcodeInfo { - char name[6]; - unsigned mode; - }; - - static const OpcodeInfo opcodeInfo[256]; - - static unsigned getOpcodeLength(uint8_t opcode); - static string disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph); - static string disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph); -}; - -const SNESSMP::OpcodeInfo SNESSMP::opcodeInfo[256] = { - //0x00 - 0x0f - { "nop ", Implied }, - { "tcall", TVector }, - { "set0 ", Direct }, - { "bbs0 ", DirectRelative }, - - { "or ", ADirect }, - { "or ", AAbsolute }, - { "or ", AIX }, - { "or ", AIDirectX }, - - { "or ", AConstant }, - { "or ", DirectDirect }, - { "or1 ", CAbsoluteBit }, - { "asl ", Direct }, - - { "asl ", Absolute }, - { "push ", P }, - { "tset ", AbsoluteA }, - { "brk ", Implied }, - - //0x10 - 0x1f - { "bpl ", Relative }, - { "tcall", TVector }, - { "clr0 ", Direct }, - { "bbc0 ", DirectRelative }, - - { "or ", ADirectX }, - { "or ", AAbsoluteX }, - { "or ", AAbsoluteY }, - { "or ", AIDirectY }, - - { "or ", DirectConstant }, - { "or ", IXIY }, - { "decw ", Direct }, - { "asl ", DirectX }, - - { "asl ", A }, - { "dec ", X }, - { "cmp ", XAbsolute }, - { "jmp ", IAbsoluteX }, - - //0x20 - 0x2f - { "clrp ", Implied }, - { "tcall", TVector }, - { "set1 ", Direct }, - { "bbs1 ", DirectRelative }, - - { "and ", ADirect }, - { "and ", AAbsolute }, - { "and ", AIX }, - { "and ", AIDirectX }, - - { "and ", AConstant }, - { "and ", DirectDirect }, - { "or1 ", CNAbsoluteBit }, - { "rol ", Direct }, - - { "rol ", Absolute }, - { "push ", A }, - { "cbne ", DirectRelative }, - { "bra ", Relative }, - - //0x30 - 0x3f - { "bmi ", Relative }, - { "tcall", TVector }, - { "clr1 ", Direct }, - { "bbc1 ", DirectRelative }, - - { "and ", ADirectX }, - { "and ", AAbsoluteX }, - { "and ", AAbsoluteY }, - { "and ", AIDirectY }, - - { "and ", DirectConstant }, - { "and ", IXIY }, - { "incw ", Direct }, - { "rol ", DirectX }, - - { "rol ", A }, - { "inc ", X }, - { "cmp ", XDirect }, - { "call ", Absolute }, - - //0x40 - 0x4f - { "setp ", Implied }, - { "tcall", TVector }, - { "set2 ", Direct }, - { "bbs2 ", DirectRelative }, - - { "eor ", ADirect }, - { "eor ", AAbsolute }, - { "eor ", AIX }, - { "eor ", AIDirectX }, - - { "eor ", AConstant }, - { "eor ", DirectDirect }, - { "and1 ", CAbsoluteBit }, - { "lsr ", Direct }, - - { "lsr ", Absolute }, - { "push ", X }, - { "tclr ", AbsoluteA }, - { "pcall", PVector }, - - //0x50 - 0x5f - { "bvc ", Relative }, - { "tcall", TVector }, - { "clr2 ", Direct }, - { "bbc2 ", DirectRelative }, - - { "eor ", ADirectX }, - { "eor ", AAbsoluteX }, - { "eor ", AAbsoluteY }, - { "eor ", AIDirectY }, - - { "eor ", DirectConstant }, - { "eor ", IXIY }, - { "cmpw ", YaDirect }, - { "lsr ", DirectX }, - - { "lsr ", A }, - { "mov ", XA }, - { "cmp ", YAbsolute }, - { "jmp ", Absolute }, - - //0x60 - 0x6f - { "clrc ", Implied }, - { "tcall", TVector }, - { "set3 ", Direct }, - { "bbs3 ", DirectRelative }, - - { "cmp ", ADirect }, - { "cmp ", AAbsolute }, - { "cmp ", AIX }, - { "cmp ", AIDirectX }, - - { "cmp ", AConstant }, - { "cmp ", DirectDirect }, - { "and1 ", CNAbsoluteBit }, - { "ror ", Direct }, - - { "ror ", Absolute }, - { "push ", Y }, - { "dbnz ", DirectRelative }, - { "ret ", Implied }, - - //0x70 - 0x7f - { "bvs ", Relative }, - { "tcall", TVector }, - { "clr3 ", Direct }, - { "bbc3 ", DirectRelative }, - - { "cmp ", ADirectX }, - { "cmp ", AAbsoluteX }, - { "cmp ", AAbsoluteY }, - { "cmp ", AIDirectY }, - - { "cmp ", DirectConstant }, - { "cmp ", IXIY }, - { "addw ", YaDirect }, - { "ror ", DirectX }, - - { "ror ", A }, - { "mov ", AX }, - { "cmp ", YDirect }, - { "reti ", Implied }, - - //0x80 - 0x8f - { "setc ", Implied }, - { "tcall", TVector }, - { "set4 ", Direct }, - { "bbs4 ", DirectRelative }, - - { "adc ", ADirect }, - { "adc ", AAbsolute }, - { "adc ", AIX }, - { "adc ", AIDirectX }, - - { "adc ", AConstant }, - { "adc ", DirectDirect }, - { "eor1 ", CAbsoluteBit }, - { "dec ", Direct }, - - { "dec ", Absolute }, - { "mov ", YConstant }, - { "pop ", P }, - { "mov ", DirectConstant }, - - //0x90 - 0x9f - { "bcc ", Relative }, - { "tcall", TVector }, - { "clr4 ", Direct }, - { "bbc4 ", DirectRelative }, - - { "adc ", ADirectX }, - { "adc ", AAbsoluteX }, - { "adc ", AAbsoluteY }, - { "adc ", AIDirectY }, - - { "adc ", DirectRelative }, - { "adc ", IXIY }, - { "subw ", YaDirect }, - { "dec ", DirectX }, - - { "dec ", A }, - { "mov ", XSp }, - { "div ", YaX }, - { "xcn ", A }, - - //0xa0 - 0xaf - { "ei ", Implied }, - { "tcall", TVector }, - { "set5 ", Direct }, - { "bbs5 ", DirectRelative }, - - { "sbc ", ADirect }, - { "sbc ", AAbsolute }, - { "sbc ", AIX }, - { "sbc ", AIDirectX }, - - { "sbc ", AConstant }, - { "sbc ", DirectDirect }, - { "mov1 ", CAbsoluteBit }, - { "inc ", Direct }, - - { "inc ", Absolute }, - { "cmp ", YConstant }, - { "pop ", A }, - { "mov ", IXPA }, - - //0xb0 - 0xbf - { "bcs ", Relative }, - { "tcall", TVector }, - { "clr5 ", Direct }, - { "bbc5 ", DirectRelative }, - - { "sbc ", ADirectX }, - { "sbc ", AAbsoluteX }, - { "sbc ", AAbsoluteY }, - { "sbc ", AIDirectY }, - - { "sbc ", DirectConstant }, - { "sbc ", IXIY }, - { "movw ", YaDirect }, - { "inc ", DirectX }, - - { "inc ", A }, - { "mov ", SpX }, - { "das ", A }, - { "mov ", AIXP }, - - //0xc0 - 0xcf - { "di ", Implied }, - { "tcall", TVector }, - { "set6 ", Direct }, - { "bbs6 ", DirectRelative }, - - { "mov ", DirectA }, - { "mov ", AbsoluteA }, - { "mov ", IXA }, - { "mov ", IDirectXA }, - - { "cmp ", XConstant }, - { "mov ", AbsoluteX }, - { "mov1 ", AbsoluteBitC }, - { "mov ", DirectY }, - - { "mov ", AbsoluteY }, - { "mov ", XConstant }, - { "pop ", X }, - { "mul ", Ya }, - - //0xd0 - 0xdf - { "bne ", Relative }, - { "tcall", TVector }, - { "clr6 ", Relative }, - { "bbc6 ", DirectRelative }, - - { "mov ", DirectXA }, - { "mov ", AbsoluteXA }, - { "mov ", AbsoluteYA }, - { "mov ", IDirectYA }, - - { "mov ", DirectX }, - { "mov ", DirectYX }, - { "movw ", DirectYa }, - { "mov ", DirectXY }, - - { "dec ", Y }, - { "mov ", AY }, - { "cbne ", DirectXRelative }, - { "daa ", A }, - - //0xe0 - 0xef - { "clrv ", Implied }, - { "tcall", TVector }, - { "set7 ", Direct }, - { "bbs7 ", DirectRelative }, - - { "mov ", ADirect }, - { "mov ", AAbsolute }, - { "mov ", AIX }, - { "mov ", AIDirectX }, - - { "mov ", AConstant }, - { "mov ", XAbsolute }, - { "not1 ", CAbsoluteBit }, - { "mov ", YDirect }, - - { "mov ", YAbsolute }, - { "notc ", Implied }, - { "pop ", Y }, - { "sleep", Implied }, - - //0xf0 - 0xff - { "beq ", Relative }, - { "tcall", TVector }, - { "clr7 ", Direct }, - { "bbc7 ", DirectRelative }, - - { "mov ", ADirectX }, - { "mov ", AAbsoluteX }, - { "mov ", AAbsoluteY }, - { "mov ", AIDirectY }, - - { "mov ", XDirect }, - { "mov ", XDirectY }, - { "mov ", DirectDirect }, - { "mov ", YDirectX }, - - { "inc ", Y }, - { "mov ", YA }, - { "dbz ", YRelative }, - { "stop ", Implied }, -}; - -inline unsigned SNESSMP::getOpcodeLength(uint8_t opcode) { - switch(opcodeInfo[opcode].mode) { default: - case Implied: return 1; // - case TVector: return 1; //0 - case Direct: return 2; //$00 - case DirectRelative: return 3; //$00,+/-$00 - case ADirect: return 2; //a,$00 - case AAbsolute: return 3; //a,$0000 - case AIX: return 1; //a,(x) - case AIDirectX: return 2; //a,($00+x) - case AConstant: return 2; //a,#$00 - case DirectDirect: return 3; //$00,$00 - case CAbsoluteBit: return 3; //c,$0000:0 - case Absolute: return 3; //$0000 - case P: return 1; //p - case AbsoluteA: return 3; //$0000,a - case Relative: return 2; //+/-$00 - case ADirectX: return 2; //a,$00+x - case AAbsoluteX: return 3; //a,$0000+x - case AAbsoluteY: return 3; //a,$0000+y - case AIDirectY: return 2; //a,($00)+y - case DirectConstant: return 3; //$00,#$00 - case IXIY: return 1; //(x),(y) - case DirectX: return 2; //$00+x - case A: return 1; //a - case X: return 1; //x - case XAbsolute: return 3; //x,$0000 - case IAbsoluteX: return 3; //($0000+x) - case CNAbsoluteBit: return 3; //c,!$0000:0 - case XDirect: return 2; //x,$00 - case PVector: return 2; //$ff00 - case YaDirect: return 2; //ya,$00 - case XA: return 1; //x,a - case YAbsolute: return 3; //y,$0000 - case Y: return 1; //y - case AX: return 1; //a,x - case YDirect: return 2; //y,$00 - case YConstant: return 2; //y,#$00 - case XSp: return 1; //x,sp - case YaX: return 1; //ya,x - case IXPA: return 1; //(x)+,a - case SpX: return 1; //sp,x - case AIXP: return 1; //a,(x)+ - case DirectA: return 2; //$00,a - case IXA: return 1; //(x),a - case IDirectXA: return 2; //($00+x),a - case XConstant: return 2; //x,#$00 - case AbsoluteX: return 3; //$0000,x - case AbsoluteBitC: return 3; //$0000:0,c - case DirectY: return 2; //$00,y - case AbsoluteY: return 3; //$0000,y - case Ya: return 1; //ya - case DirectXA: return 2; //$00+x,a - case AbsoluteXA: return 3; //$0000+x,a - case AbsoluteYA: return 3; //$0000+y,a - case IDirectYA: return 2; //($00)+y,a - case DirectYX: return 2; //$00+y,x - case DirectYa: return 2; //$00,ya - case DirectXY: return 2; //$00+x,y - case AY: return 1; //a,y - case DirectXRelative: return 3; //$00+x,+/-$00 - case XDirectY: return 2; //x,$00+y - case YDirectX: return 2; //y,$00+x - case YA: return 1; //y,a - case YRelative: return 2; //y,+/-$00 - } -} - -inline string SNESSMP::disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph) { - string name = opcodeInfo[opcode].name; - unsigned mode = opcodeInfo[opcode].mode; - unsigned pa = (ph << 8) + pl; - - if(mode == Implied) return name; - if(mode == TVector) return { name, " ", opcode >> 4 }; - if(mode == Direct) return { name, " $", hex<2>(pl) }; - if(mode == DirectRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; - if(mode == ADirect) return { name, " a,$", hex<2>(pl) }; - if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) }; - if(mode == AIX) return { name, "a,(x)" }; - if(mode == AIDirectX) return { name, " a,($", hex<2>(pl), "+x)" }; - if(mode == AConstant) return { name, " a,#$", hex<2>(pl) }; - if(mode == DirectDirect) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) }; - if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; - if(mode == Absolute) return { name, " $", hex<4>(pa) }; - if(mode == P) return { name, " p" }; - if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" }; - if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) }; - if(mode == ADirectX) return { name, " a,$", hex<2>(pl), "+x" }; - if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" }; - if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" }; - if(mode == AIDirectY) return { name, " a,($", hex<2>(pl), ")+y" }; - if(mode == DirectConstant) return { name, " $", hex<2>(ph), ",#$", hex<2>(pl) }; - if(mode == IXIY) return { name, " (x),(y)" }; - if(mode == DirectX) return { name, " $", hex<2>(pl), "+x" }; - if(mode == A) return { name, " a" }; - if(mode == X) return { name, " x" }; - if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) }; - if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" }; - if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; - if(mode == XDirect) return { name, " x,$", hex<2>(pl) }; - if(mode == PVector) return { name, " $ff", hex<2>(pl) }; - if(mode == YaDirect) return { name, " ya,$", hex<2>(pl) }; - if(mode == XA) return { name, " x,a" }; - if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) }; - if(mode == Y) return { name, " y" }; - if(mode == AX) return { name, " a,x" }; - if(mode == YDirect) return { name, " y,$", hex<2>(pl) }; - if(mode == YConstant) return { name, " y,#$", hex<2>(pl) }; - if(mode == XSp) return { name, " x,sp" }; - if(mode == YaX) return { name, " ya,x" }; - if(mode == IXPA) return { name, " (x)+,a" }; - if(mode == SpX) return { name, " sp,x" }; - if(mode == AIXP) return { name, " a,(x)+" }; - if(mode == DirectA) return { name, " $", hex<2>(pl), ",a" }; - if(mode == IXA) return { name, " (x),a" }; - if(mode == IDirectXA) return { name, " ($", hex<2>(pl), "+x),a" }; - if(mode == XConstant) return { name, " x,#$", hex<2>(pl) }; - if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" }; - if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" }; - if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" }; - if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" }; - if(mode == Ya) return { name, " ya" }; - if(mode == DirectXA) return { name, " $", hex<2>(pl), "+x,a" }; - if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" }; - if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" }; - if(mode == IDirectYA) return { name, " ($", hex<2>(pl), ")+y,a" }; - if(mode == DirectYX) return { name, " $", hex<2>(pl), "+y,x" }; - if(mode == DirectYa) return { name, " $", hex<2>(pl), ",ya" }; - if(mode == DirectXY) return { name, " $", hex<2>(pl), "+x,y" }; - if(mode == AY) return { name, " a,y" }; - if(mode == DirectXRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; - if(mode == XDirectY) return { name, " x,$", hex<2>(pl), "+y" }; - if(mode == YDirectX) return { name, " y,$", hex<2>(pl), "+x" }; - if(mode == YA) return { name, " y,a" }; - if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) }; - - return ""; -} - -inline string SNESSMP::disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph) { - string name = opcodeInfo[opcode].name; - unsigned mode = opcodeInfo[opcode].mode; - unsigned pdl = (p << 8) + pl; - unsigned pdh = (p << 8) + ph; - unsigned pa = (ph << 8) + pl; - - if(mode == Implied) return name; - if(mode == TVector) return { name, " ", opcode >> 4 }; - if(mode == Direct) return { name, " $", hex<3>(pdl) }; - if(mode == DirectRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; - if(mode == ADirect) return { name, " a,$", hex<3>(pdl) }; - if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) }; - if(mode == AIX) return { name, "a,(x)" }; - if(mode == AIDirectX) return { name, " a,($", hex<3>(pdl), "+x)" }; - if(mode == AConstant) return { name, " a,#$", hex<2>(pl) }; - if(mode == DirectDirect) return { name, " $", hex<3>(pdh), ",$", hex<3>(pdl) }; - if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; - if(mode == Absolute) return { name, " $", hex<4>(pa) }; - if(mode == P) return { name, " p" }; - if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" }; - if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) }; - if(mode == ADirectX) return { name, " a,$", hex<3>(pdl), "+x" }; - if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" }; - if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" }; - if(mode == AIDirectY) return { name, " a,($", hex<3>(pdl), ")+y" }; - if(mode == DirectConstant) return { name, " $", hex<3>(pdh), ",#$", hex<2>(pl) }; - if(mode == IXIY) return { name, " (x),(y)" }; - if(mode == DirectX) return { name, " $", hex<3>(pdl), "+x" }; - if(mode == A) return { name, " a" }; - if(mode == X) return { name, " x" }; - if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) }; - if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" }; - if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; - if(mode == XDirect) return { name, " x,$", hex<3>(pdl) }; - if(mode == PVector) return { name, " $ff", hex<2>(pl) }; - if(mode == YaDirect) return { name, " ya,$", hex<3>(pdl) }; - if(mode == XA) return { name, " x,a" }; - if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) }; - if(mode == Y) return { name, " y" }; - if(mode == AX) return { name, " a,x" }; - if(mode == YDirect) return { name, " y,$", hex<3>(pdl) }; - if(mode == YConstant) return { name, " y,#$", hex<2>(pl) }; - if(mode == XSp) return { name, " x,sp" }; - if(mode == YaX) return { name, " ya,x" }; - if(mode == IXPA) return { name, " (x)+,a" }; - if(mode == SpX) return { name, " sp,x" }; - if(mode == AIXP) return { name, " a,(x)+" }; - if(mode == DirectA) return { name, " $", hex<3>(pdl), ",a" }; - if(mode == IXA) return { name, " (x),a" }; - if(mode == IDirectXA) return { name, " ($", hex<3>(pdl), "+x),a" }; - if(mode == XConstant) return { name, " x,#$", hex<2>(pl) }; - if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" }; - if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" }; - if(mode == DirectY) return { name, " $", hex<3>(pdl), ",y" }; - if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" }; - if(mode == Ya) return { name, " ya" }; - if(mode == DirectXA) return { name, " $", hex<3>(pdl), "+x,a" }; - if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" }; - if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" }; - if(mode == IDirectYA) return { name, " ($", hex<3>(pdl), ")+y,a" }; - if(mode == DirectYX) return { name, " $", hex<3>(pdl), "+y,x" }; - if(mode == DirectYa) return { name, " $", hex<3>(pdl), ",ya" }; - if(mode == DirectXY) return { name, " $", hex<3>(pdl), "+x,y" }; - if(mode == AY) return { name, " a,y" }; - if(mode == DirectXRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; - if(mode == XDirectY) return { name, " x,$", hex<3>(pdl), "+y" }; - if(mode == YDirectX) return { name, " y,$", hex<3>(pdl), "+x" }; - if(mode == YA) return { name, " y,a" }; - if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) }; - - return ""; -} - -} - -#endif diff --git a/snesfilter/nall/sort.hpp b/snesfilter/nall/sort.hpp deleted file mode 100755 index 23c317a5..00000000 --- a/snesfilter/nall/sort.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef NALL_SORT_HPP -#define NALL_SORT_HPP - -#include - -//class: merge sort -//average: O(n log n) -//worst: O(n log n) -//memory: O(n) -//stack: O(log n) -//stable?: yes - -//notes: -//there are two primary reasons for choosing merge sort -//over the (usually) faster quick sort*: -//1: it is a stable sort. -//2: it lacks O(n^2) worst-case overhead. -//(* which is also O(n log n) in the average case.) - -namespace nall { - template - void sort(T list[], unsigned length) { - if(length <= 1) return; //nothing to sort - - //use insertion sort to quickly sort smaller blocks - if(length < 64) { - for(unsigned i = 0; i < length; i++) { - unsigned min = i; - for(unsigned j = i + 1; j < length; j++) { - if(list[j] < list[min]) min = j; - } - if(min != i) swap(list[i], list[min]); - } - return; - } - - //split list in half and recursively sort both - unsigned middle = length / 2; - sort(list, middle); - sort(list + middle, length - middle); - - //left and right are sorted here; perform merge sort - T *buffer = new T[length]; - unsigned offset = 0; - unsigned left = 0; - unsigned right = middle; - while(left < middle && right < length) { - if(list[left] < list[right]) { - buffer[offset++] = list[left++]; - } else { - buffer[offset++] = list[right++]; - } - } - while(left < middle) buffer[offset++] = list[left++]; - while(right < length) buffer[offset++] = list[right++]; - - for(unsigned i = 0; i < length; i++) list[i] = buffer[i]; - delete[] buffer; - } -} - -#endif diff --git a/snesfilter/nall/stack.hpp b/snesfilter/nall/stack.hpp deleted file mode 100755 index fe8e16a1..00000000 --- a/snesfilter/nall/stack.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef NALL_STACK_HPP -#define NALL_STACK_HPP - -#include - -namespace nall { - template struct stack : public linear_vector { - void push(const T &value) { - linear_vector::append(value); - } - - T pull() { - if(linear_vector::size() == 0) throw; - T value = linear_vector::operator[](linear_vector::size() - 1); - linear_vector::remove(linear_vector::size() - 1); - return value; - } - - T& operator()() { - if(linear_vector::size() == 0) throw; - return linear_vector::operator[](linear_vector::size() - 1); - } - }; -} - -#endif diff --git a/snesfilter/nall/static.hpp b/snesfilter/nall/static.hpp deleted file mode 100755 index 4acb9fd0..00000000 --- a/snesfilter/nall/static.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef NALL_STATIC_HPP -#define NALL_STATIC_HPP - -namespace nall { - template struct static_if { typedef T type; }; - template struct static_if { typedef F type; }; - template struct mp_static_if { typedef typename static_if::type type; }; - - template struct static_and { enum { value = false }; }; - template<> struct static_and { enum { value = true }; }; - template struct mp_static_and { enum { value = static_and::value }; }; - - template struct static_or { enum { value = false }; }; - template<> struct static_or { enum { value = true }; }; - template<> struct static_or { enum { value = true }; }; - template<> struct static_or { enum { value = true }; }; - template struct mp_static_or { enum { value = static_or::value }; }; -} - -#endif diff --git a/snesfilter/nall/string/filename.hpp b/snesfilter/nall/string/filename.hpp deleted file mode 100755 index 6dea67fc..00000000 --- a/snesfilter/nall/string/filename.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -// "foo/bar.c" -> "foo/" -// "foo/" -> "foo/" -// "bar.c" -> "./" -inline string dir(char const *name) { - string result = name; - for(signed i = strlen(result); i >= 0; i--) { - if(result[i] == '/' || result[i] == '\\') { - result[i + 1] = 0; - break; - } - if(i == 0) result = "./"; - } - return result; -} - -// "foo/bar.c" -> "bar.c" -inline string notdir(char const *name) { - for(signed i = strlen(name); i >= 0; i--) { - if(name[i] == '/' || name[i] == '\\') { - name += i + 1; - break; - } - } - string result = name; - return result; -} - -// "foo/bar.c" -> "foo/bar" -inline string basename(char const *name) { - string result = name; - for(signed i = strlen(result); i >= 0; i--) { - if(result[i] == '/' || result[i] == '\\') { - //file has no extension - break; - } - if(result[i] == '.') { - result[i] = 0; - break; - } - } - return result; -} - -// "foo/bar.c" -> "c" -inline string extension(char const *name) { - for(signed i = strlen(name); i >= 0; i--) { - if(name[i] == '.') { - name += i + 1; - break; - } - } - string result = name; - return result; -} - -} - -#endif diff --git a/snesfilter/nall/string/math.hpp b/snesfilter/nall/string/math.hpp deleted file mode 100755 index 8356e162..00000000 --- a/snesfilter/nall/string/math.hpp +++ /dev/null @@ -1,167 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -static function eval_fallback; - -static int eval_integer(const char *&s) { - if(!*s) throw "unrecognized_integer"; - int value = 0, x = *s, y = *(s + 1); - - //hexadecimal - if(x == '0' && (y == 'X' || y == 'x')) { - s += 2; - while(true) { - if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; } - if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; } - if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; } - return value; - } - } - - //binary - if(x == '0' && (y == 'B' || y == 'b')) { - s += 2; - while(true) { - if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; } - return value; - } - } - - //octal (or decimal '0') - if(x == '0') { - s += 1; - while(true) { - if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; } - return value; - } - } - - //decimal - if(x >= '0' && x <= '9') { - while(true) { - if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; } - return value; - } - } - - //char - if(x == '\'' && y != '\'') { - s += 1; - while(true) { - value = value * 256 + *s++; - if(*s == '\'') { s += 1; return value; } - if(!*s) throw "mismatched_char"; - } - } - - throw "unrecognized_integer"; -} - -static int eval(const char *&s, int depth = 0) { - while(*s == ' ' || *s == '\t') s++; //trim whitespace - if(!*s) throw "unrecognized_token"; - int value = 0, x = *s, y = *(s + 1); - - if(*s == '(') { - value = eval(++s, 1); - if(*s++ != ')') throw "mismatched_group"; - } - - else if(x == '!') value = !eval(++s, 13); - else if(x == '~') value = ~eval(++s, 13); - else if(x == '+') value = +eval(++s, 13); - else if(x == '-') value = -eval(++s, 13); - - else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s); - - else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing - - else throw "unrecognized_token"; - - while(true) { - while(*s == ' ' || *s == '\t') s++; //trim whitespace - if(!*s) break; - x = *s, y = *(s + 1); - - if(depth >= 13) break; - if(x == '*') { value *= eval(++s, 13); continue; } - if(x == '/') { int result = eval(++s, 13); if(result == 0) throw "division_by_zero"; value /= result; continue; } - if(x == '%') { int result = eval(++s, 13); if(result == 0) throw "division_by_zero"; value %= result; continue; } - - if(depth >= 12) break; - if(x == '+') { value += eval(++s, 12); continue; } - if(x == '-') { value -= eval(++s, 12); continue; } - - if(depth >= 11) break; - if(x == '<' && y == '<') { value <<= eval(++++s, 11); continue; } - if(x == '>' && y == '>') { value >>= eval(++++s, 11); continue; } - - if(depth >= 10) break; - if(x == '<' && y == '=') { value = value <= eval(++++s, 10); continue; } - if(x == '>' && y == '=') { value = value >= eval(++++s, 10); continue; } - if(x == '<') { value = value < eval(++s, 10); continue; } - if(x == '>') { value = value > eval(++s, 10); continue; } - - if(depth >= 9) break; - if(x == '=' && y == '=') { value = value == eval(++++s, 9); continue; } - if(x == '!' && y == '=') { value = value != eval(++++s, 9); continue; } - - if(depth >= 8) break; - if(x == '&' && y != '&') { value = value & eval(++s, 8); continue; } - - if(depth >= 7) break; - if(x == '^' && y != '^') { value = value ^ eval(++s, 7); continue; } - - if(depth >= 6) break; - if(x == '|' && y != '|') { value = value | eval(++s, 6); continue; } - - if(depth >= 5) break; - if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; } - - if(depth >= 4) break; - if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; } - - if(depth >= 3) break; - if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; } - - if(x == '?') { - int lhs = eval(++s, 2); - if(*s != ':') throw "mismatched_ternary"; - int rhs = eval(++s, 2); - value = value ? lhs : rhs; - continue; - } - if(depth >= 2) break; - - if(depth > 0 && x == ')') break; - - throw "unrecognized_token"; - } - - return value; -} - -bool strint(const char *s, int &result) { - try { - result = eval_integer(s); - return true; - } catch(const char*) { - result = 0; - return false; - } -} - -bool strmath(const char *s, int &result) { - try { - result = eval(s); - return true; - } catch(const char*) { - result = 0; - return false; - } -} - -} - -#endif diff --git a/snesfilter/nall/string/platform.hpp b/snesfilter/nall/string/platform.hpp deleted file mode 100755 index 83a5fbae..00000000 --- a/snesfilter/nall/string/platform.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -string currentpath() { - char path[PATH_MAX]; - if(::getcwd(path)) { - string result(path); - result.transform("\\", "/"); - if(result.endswith("/") == false) result.append("/"); - return result; - } - return "./"; -} - -string userpath() { - char path[PATH_MAX]; - if(::userpath(path)) { - string result(path); - result.transform("\\", "/"); - if(result.endswith("/") == false) result.append("/"); - return result; - } - return currentpath(); -} - -string realpath(const char *name) { - char path[PATH_MAX]; - if(::realpath(name, path)) { - string result(path); - result.transform("\\", "/"); - return result; - } - return userpath(); -} - -} - -#endif diff --git a/snesfilter/nall/string/strl.hpp b/snesfilter/nall/string/strl.hpp deleted file mode 100755 index 44f6d6f7..00000000 --- a/snesfilter/nall/string/strl.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -//strlcpy, strlcat based on OpenBSD implementation by Todd C. Miller - -//return = strlen(src) -unsigned strlcpy(char *dest, const char *src, unsigned length) { - char *d = dest; - const char *s = src; - unsigned n = length; - - if(n) { - while(--n && (*d++ = *s++)); //copy as many bytes as possible, or until null terminator reached - } - - if(!n) { - if(length) *d = 0; - while(*s++); //traverse rest of s, so that s - src == strlen(src) - } - - return (s - src - 1); //return length of copied string, sans null terminator -} - -//return = strlen(src) + min(length, strlen(dest)) -unsigned strlcat(char *dest, const char *src, unsigned length) { - char *d = dest; - const char *s = src; - unsigned n = length; - - while(n-- && *d) d++; //find end of dest - unsigned dlength = d - dest; - n = length - dlength; //subtract length of dest from maximum string length - - if(!n) return dlength + strlen(s); - - while(*s) { - if(n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = 0; - - return dlength + (s - src); //return length of resulting string, sans null terminator -} - -} - -#endif diff --git a/snesfilter/nall/test/cc.bat b/snesfilter/nall/test/cc.bat deleted file mode 100755 index f6434960..00000000 --- a/snesfilter/nall/test/cc.bat +++ /dev/null @@ -1,2 +0,0 @@ -g++ -std=gnu++0x -O3 -fomit-frame-pointer -s -o test test.cpp -I../.. -lws2_32 -@pause diff --git a/snesfilter/nall/test/cc.sh b/snesfilter/nall/test/cc.sh deleted file mode 100755 index 142a1b0c..00000000 --- a/snesfilter/nall/test/cc.sh +++ /dev/null @@ -1,2 +0,0 @@ -g++-4.6 -std=gnu++0x -g -o test test.cpp -I../.. -#g++-4.6 -std=gnu++0x -O3 -fomit-frame-pointer -s -o test test.cpp -I../.. diff --git a/snesfilter/nall/test/document.bml b/snesfilter/nall/test/document.bml deleted file mode 100755 index 25773f2c..00000000 --- a/snesfilter/nall/test/document.bml +++ /dev/null @@ -1,14 +0,0 @@ -# bml version=1.0 -cartridge=SNES region=NTSC origin:United States - title:The Legend of Zelda: A Link to the Past - empty-line~ - description~ language:English - Gannon has kidnapped princess Zelda. - Help Link rescue her!! - pcb:SHVC-1A3M-30 - rom - map mode=linear address=00-3f:8000-ffff - map mode=linear address=80-bf:8000-ffff - ram battery - map mode=linear address=70-7f:0000-7fff - map mode=linear address=f0-ff:0000-7fff diff --git a/snesfilter/nall/test/test b/snesfilter/nall/test/test deleted file mode 100755 index d12c2b3737c9797c3ccd51db7448ae055f891415..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 250304 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
HEW$$QumSRahOS1Y4H-=0MU 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 LkJDv|t}Oox=h-eW diff --git a/snesfilter/nall/test/test.cpp b/snesfilter/nall/test/test.cpp deleted file mode 100755 index e2613b20..00000000 --- a/snesfilter/nall/test/test.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -using namespace nall; - -int main() { - image x(0, 64, 65535ull << 48, 65535ull << 32, 65535ull << 16, 65535ull << 0); - x.allocate(4, 1); - - uint64_t *data = (uint64_t*)x.data; - data[0] = 0xffffffffffffffffull; - data[1] = 0x0000ffff00000000ull; - data[2] = 0x00000000ffff0000ull; - data[3] = 0x000000000000ffffull; - - x.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); - - uint32_t *output = (uint32_t*)x.data; - print(hex<8>(output[0]), "\n"); - print(hex<8>(output[1]), "\n"); - print(hex<8>(output[2]), "\n"); - print(hex<8>(output[3]), "\n"); - - return 0; -} - -/* -int main(int argc, char **argv) { - string text; - text.readfile("document.bml"); - BML::Document document(text); - if(document.error) print(document.error, "\n"); - - for(auto &a : document) { - print("", a.name, ":", a.value, ";\n"); - for(auto &b : a) { - print(" ", b.name, ":", b.value, ";\n"); - for(auto &c : b) { - print(" ", c.name, ":", c.value, ";\n"); - for(auto &d : c) { - print(" ", d.name, ":", d.value, ";\n"); - } - } - } - } - -//print(document["cartridge"]["title"].value, "\n"); - - return 0; -} -*/ diff --git a/snesfilter/nall/varint.hpp b/snesfilter/nall/varint.hpp deleted file mode 100755 index d91ea2a5..00000000 --- a/snesfilter/nall/varint.hpp +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef NALL_VARINT_HPP -#define NALL_VARINT_HPP - -#include -#include -#include - -namespace nall { - template class uint_t { - private: - unsigned data; - - public: - inline operator unsigned() const { return data; } - inline unsigned operator ++(int) { unsigned r = data; data = uclip(data + 1); return r; } - inline unsigned operator --(int) { unsigned r = data; data = uclip(data - 1); return r; } - inline unsigned operator ++() { return data = uclip(data + 1); } - inline unsigned operator --() { return data = uclip(data - 1); } - inline unsigned operator =(const unsigned i) { return data = uclip(i); } - inline unsigned operator |=(const unsigned i) { return data = uclip(data | i); } - inline unsigned operator ^=(const unsigned i) { return data = uclip(data ^ i); } - inline unsigned operator &=(const unsigned i) { return data = uclip(data & i); } - inline unsigned operator<<=(const unsigned i) { return data = uclip(data << i); } - inline unsigned operator>>=(const unsigned i) { return data = uclip(data >> i); } - inline unsigned operator +=(const unsigned i) { return data = uclip(data + i); } - inline unsigned operator -=(const unsigned i) { return data = uclip(data - i); } - inline unsigned operator *=(const unsigned i) { return data = uclip(data * i); } - inline unsigned operator /=(const unsigned i) { return data = uclip(data / i); } - inline unsigned operator %=(const unsigned i) { return data = uclip(data % i); } - - inline uint_t() : data(0) {} - inline uint_t(const unsigned i) : data(uclip(i)) {} - - template inline unsigned operator=(const uint_t &i) { return data = uclip((unsigned)i); } - template inline uint_t(const uint_t &i) : data(uclip(i)) {} - }; - - template class int_t { - private: - signed data; - - public: - inline operator signed() const { return data; } - inline signed operator ++(int) { signed r = data; data = sclip(data + 1); return r; } - inline signed operator --(int) { signed r = data; data = sclip(data - 1); return r; } - inline signed operator ++() { return data = sclip(data + 1); } - inline signed operator --() { return data = sclip(data - 1); } - inline signed operator =(const signed i) { return data = sclip(i); } - inline signed operator |=(const signed i) { return data = sclip(data | i); } - inline signed operator ^=(const signed i) { return data = sclip(data ^ i); } - inline signed operator &=(const signed i) { return data = sclip(data & i); } - inline signed operator<<=(const signed i) { return data = sclip(data << i); } - inline signed operator>>=(const signed i) { return data = sclip(data >> i); } - inline signed operator +=(const signed i) { return data = sclip(data + i); } - inline signed operator -=(const signed i) { return data = sclip(data - i); } - inline signed operator *=(const signed i) { return data = sclip(data * i); } - inline signed operator /=(const signed i) { return data = sclip(data / i); } - inline signed operator %=(const signed i) { return data = sclip(data % i); } - - inline int_t() : data(0) {} - inline int_t(const signed i) : data(sclip(i)) {} - }; - - class varuint_t { - private: - unsigned data; - unsigned mask; - - public: - inline operator unsigned() const { return data; } - inline unsigned operator ++(int) { unsigned r = data; data = (data + 1) & mask; return r; } - inline unsigned operator --(int) { unsigned r = data; data = (data - 1) & mask; return r; } - inline unsigned operator ++() { return data = (data + 1) & mask; } - inline unsigned operator --() { return data = (data - 1) & mask; } - inline unsigned operator =(const unsigned i) { return data = (i) & mask; } - inline unsigned operator |=(const unsigned i) { return data = (data | i) & mask; } - inline unsigned operator ^=(const unsigned i) { return data = (data ^ i) & mask; } - inline unsigned operator &=(const unsigned i) { return data = (data & i) & mask; } - inline unsigned operator<<=(const unsigned i) { return data = (data << i) & mask; } - inline unsigned operator>>=(const unsigned i) { return data = (data >> i) & mask; } - inline unsigned operator +=(const unsigned i) { return data = (data + i) & mask; } - inline unsigned operator -=(const unsigned i) { return data = (data - i) & mask; } - inline unsigned operator *=(const unsigned i) { return data = (data * i) & mask; } - inline unsigned operator /=(const unsigned i) { return data = (data / i) & mask; } - inline unsigned operator %=(const unsigned i) { return data = (data % i) & mask; } - - inline void bits(unsigned bits) { mask = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1); data &= mask; } - inline varuint_t() : data(0), mask(~0U) {} - inline varuint_t(const unsigned i) : data(i), mask(~0U) {} - }; - - class varuintmax_t { - private: - uintmax_t data; - uintmax_t mask; - - public: - inline operator uintmax_t() const { return data; } - inline uintmax_t operator ++(int) { uintmax_t r = data; data = (data + 1) & mask; return r; } - inline uintmax_t operator --(int) { uintmax_t r = data; data = (data - 1) & mask; return r; } - inline uintmax_t operator ++() { return data = (data + 1) & mask; } - inline uintmax_t operator --() { return data = (data - 1) & mask; } - inline uintmax_t operator =(const uintmax_t i) { return data = (i) & mask; } - inline uintmax_t operator |=(const uintmax_t i) { return data = (data | i) & mask; } - inline uintmax_t operator ^=(const uintmax_t i) { return data = (data ^ i) & mask; } - inline uintmax_t operator &=(const uintmax_t i) { return data = (data & i) & mask; } - inline uintmax_t operator<<=(const uintmax_t i) { return data = (data << i) & mask; } - inline uintmax_t operator>>=(const uintmax_t i) { return data = (data >> i) & mask; } - inline uintmax_t operator +=(const uintmax_t i) { return data = (data + i) & mask; } - inline uintmax_t operator -=(const uintmax_t i) { return data = (data - i) & mask; } - inline uintmax_t operator *=(const uintmax_t i) { return data = (data * i) & mask; } - inline uintmax_t operator /=(const uintmax_t i) { return data = (data / i) & mask; } - inline uintmax_t operator %=(const uintmax_t i) { return data = (data % i) & mask; } - - inline void bits(unsigned bits) { mask = (1ULL << (bits - 1)) + ((1ULL << (bits - 1)) - 1); data &= mask; } - inline varuintmax_t() : data(0), mask(~0ULL) {} - inline varuintmax_t(const uintmax_t i) : data(i), mask(~0ULL) {} - }; -} - -#endif diff --git a/snesfilter/nall/vector.hpp b/snesfilter/nall/vector.hpp deleted file mode 100755 index 1af16d29..00000000 --- a/snesfilter/nall/vector.hpp +++ /dev/null @@ -1,414 +0,0 @@ -#ifndef NALL_VECTOR_HPP -#define NALL_VECTOR_HPP - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace nall { - template struct vector { - struct exception_out_of_bounds{}; - - protected: - T *pool; - unsigned poolsize; - unsigned objectsize; - - public: - unsigned size() const { return objectsize; } - unsigned capacity() const { return poolsize; } - - void reset() { - if(pool) { - for(unsigned n = 0; n < objectsize; n++) pool[n].~T(); - free(pool); - } - pool = nullptr; - poolsize = 0; - objectsize = 0; - } - - void reserve(unsigned size) { - size = bit::round(size); //amortize growth - T *copy = (T*)calloc(size, sizeof(T)); - for(unsigned n = 0; n < min(size, objectsize); n++) new(copy + n) T(pool[n]); - for(unsigned n = 0; n < objectsize; n++) pool[n].~T(); - free(pool); - pool = copy; - poolsize = size; - objectsize = min(size, objectsize); - } - - template - void append(const T& data, Args&&... args) { - append(data); - append(std::forward(args)...); - } - - void append(const T& data) { - if(objectsize + 1 > poolsize) reserve(objectsize + 1); - new(pool + objectsize++) T(data); - } - - void prepend(const T& data) { - append(data); - for(unsigned n = objectsize - 1; n; n--) swap(pool[n], pool[n - 1]); - } - - void remove(unsigned index, unsigned count = 1) { - for(unsigned n = index; count + n < objectsize; n++) { - pool[n] = pool[count + n]; - } - objectsize = (count + index >= objectsize) ? index : objectsize - count; - } - - //access - inline T& operator[](unsigned position) { - if(position >= objectsize) throw exception_out_of_bounds(); - return pool[position]; - } - - inline const T& operator[](unsigned position) const { - if(position >= objectsize) throw exception_out_of_bounds(); - return pool[position]; - } - - inline const T& operator()(unsigned position, const T& data) const { - if(position >= objectsize) return data; - return pool[position]; - } - - //iteration - T* begin() { return &pool[0]; } - T* end() { return &pool[objectsize]; } - const T* begin() const { return &pool[0]; } - const T* end() const { return &pool[objectsize]; } - - //copy - inline vector& operator=(const vector &source) { - reset(); - reserve(source.capacity()); - for(auto &data : source) append(data); - return *this; - } - - vector(const vector &source) : pool(nullptr), poolsize(0), objectsize(0) { - operator=(source); - } - - //move - inline vector& operator=(vector &&source) { - reset(); - pool = source.pool, poolsize = source.poolsize, objectsize = source.objectsize; - source.pool = nullptr, source.poolsize = 0, source.objectsize = 0; - return *this; - } - - vector(vector &&source) : pool(nullptr), poolsize(0), objectsize(0) { - operator=(std::move(source)); - } - - //construction - vector() : pool(nullptr), poolsize(0), objectsize(0) { - } - - vector(std::initializer_list list) : pool(nullptr), poolsize(0), objectsize(0) { - for(auto &data : list) append(data); - } - - ~vector() { - reset(); - } - }; - - //linear_vector - //memory: O(capacity * 2) - // - //linear_vector uses placement new + manual destructor calls to create a - //contiguous block of memory for all objects. accessing individual elements - //is fast, though resizing the array incurs significant overhead. - //reserve() overhead is reduced from quadratic time to amortized constant time - //by resizing twice as much as requested. - // - //if objects hold memory address references to themselves (introspection), a - //valid copy constructor will be needed to keep pointers valid. - - template struct linear_vector { - protected: - T *pool; - unsigned poolsize, objectsize; - - public: - unsigned size() const { return objectsize; } - unsigned capacity() const { return poolsize; } - - void reset() { - if(pool) { - for(unsigned i = 0; i < objectsize; i++) pool[i].~T(); - free(pool); - } - pool = nullptr; - poolsize = 0; - objectsize = 0; - } - - void reserve(unsigned newsize) { - newsize = bit::round(newsize); //round to nearest power of two (for amortized growth) - - T *poolcopy = (T*)calloc(newsize, sizeof(T)); - for(unsigned i = 0; i < min(objectsize, newsize); i++) new(poolcopy + i) T(pool[i]); - for(unsigned i = 0; i < objectsize; i++) pool[i].~T(); - free(pool); - pool = poolcopy; - poolsize = newsize; - objectsize = min(objectsize, newsize); - } - - void resize(unsigned newsize) { - if(newsize > poolsize) reserve(newsize); - - if(newsize < objectsize) { - //vector is shrinking; destroy excess objects - for(unsigned i = newsize; i < objectsize; i++) pool[i].~T(); - } else if(newsize > objectsize) { - //vector is expanding; allocate new objects - for(unsigned i = objectsize; i < newsize; i++) new(pool + i) T; - } - - objectsize = newsize; - } - - void append(const T data) { - if(objectsize + 1 > poolsize) reserve(objectsize + 1); - new(pool + objectsize++) T(data); - } - - template void insert(unsigned index, const U list) { - linear_vector merged; - for(unsigned i = 0; i < index; i++) merged.append(pool[i]); - for(auto &item : list) merged.append(item); - for(unsigned i = index; i < objectsize; i++) merged.append(pool[i]); - operator=(merged); - } - - void insert(unsigned index, const T item) { - insert(index, linear_vector{ item }); - } - - void remove(unsigned index, unsigned count = 1) { - for(unsigned i = index; count + i < objectsize; i++) { - pool[i] = pool[count + i]; - } - if(count + index >= objectsize) resize(index); //every element >= index was removed - else resize(objectsize - count); - } - - linear_vector() : pool(nullptr), poolsize(0), objectsize(0) { - } - - linear_vector(std::initializer_list list) : pool(nullptr), poolsize(0), objectsize(0) { - for(const T *p = list.begin(); p != list.end(); ++p) append(*p); - } - - ~linear_vector() { - reset(); - } - - //copy - inline linear_vector& operator=(const linear_vector &source) { - reset(); - reserve(source.capacity()); - resize(source.size()); - for(unsigned i = 0; i < source.size(); i++) operator[](i) = source.operator[](i); - return *this; - } - - linear_vector(const linear_vector &source) : pool(nullptr), poolsize(0), objectsize(0) { - operator=(source); - } - - //move - inline linear_vector& operator=(linear_vector &&source) { - reset(); - pool = source.pool; - poolsize = source.poolsize; - objectsize = source.objectsize; - source.pool = nullptr; - source.reset(); - return *this; - } - - linear_vector(linear_vector &&source) : pool(nullptr), poolsize(0), objectsize(0) { - operator=(std::move(source)); - } - - //index - inline T& operator[](unsigned index) { - if(index >= objectsize) resize(index + 1); - return pool[index]; - } - - inline const T& operator[](unsigned index) const { - if(index >= objectsize) throw "vector[] out of bounds"; - return pool[index]; - } - - //iteration - T* begin() { return &pool[0]; } - T* end() { return &pool[objectsize]; } - const T* begin() const { return &pool[0]; } - const T* end() const { return &pool[objectsize]; } - }; - - //pointer_vector - //memory: O(1) - // - //pointer_vector keeps an array of pointers to each vector object. this adds - //significant overhead to individual accesses, but allows for optimal memory - //utilization. - // - //by guaranteeing that the base memory address of each objects never changes, - //this avoids the need for an object to have a valid copy constructor. - - template struct pointer_vector { - protected: - T **pool; - unsigned poolsize, objectsize; - - public: - unsigned size() const { return objectsize; } - unsigned capacity() const { return poolsize; } - - void reset() { - if(pool) { - for(unsigned i = 0; i < objectsize; i++) { if(pool[i]) delete pool[i]; } - free(pool); - } - pool = nullptr; - poolsize = 0; - objectsize = 0; - } - - void reserve(unsigned newsize) { - newsize = bit::round(newsize); //round to nearest power of two (for amortized growth) - - for(unsigned i = newsize; i < objectsize; i++) { - if(pool[i]) { delete pool[i]; pool[i] = 0; } - } - - pool = (T**)realloc(pool, newsize * sizeof(T*)); - for(unsigned i = poolsize; i < newsize; i++) pool[i] = 0; - poolsize = newsize; - objectsize = min(objectsize, newsize); - } - - void resize(unsigned newsize) { - if(newsize > poolsize) reserve(newsize); - - for(unsigned i = newsize; i < objectsize; i++) { - if(pool[i]) { delete pool[i]; pool[i] = 0; } - } - - objectsize = newsize; - } - - void append(const T data) { - if(objectsize + 1 > poolsize) reserve(objectsize + 1); - pool[objectsize++] = new T(data); - } - - template void insert(unsigned index, const U list) { - pointer_vector merged; - for(unsigned i = 0; i < index; i++) merged.append(*pool[i]); - for(auto &item : list) merged.append(item); - for(unsigned i = index; i < objectsize; i++) merged.append(*pool[i]); - operator=(merged); - } - - void insert(unsigned index, const T item) { - insert(index, pointer_vector{ item }); - } - - void remove(unsigned index, unsigned count = 1) { - for(unsigned i = index; count + i < objectsize; i++) { - *pool[i] = *pool[count + i]; - } - if(count + index >= objectsize) resize(index); //every element >= index was removed - else resize(objectsize - count); - } - - pointer_vector() : pool(nullptr), poolsize(0), objectsize(0) { - } - - pointer_vector(std::initializer_list list) : pool(nullptr), poolsize(0), objectsize(0) { - for(const T *p = list.begin(); p != list.end(); ++p) append(*p); - } - - ~pointer_vector() { - reset(); - } - - //copy - inline pointer_vector& operator=(const pointer_vector &source) { - reset(); - reserve(source.capacity()); - resize(source.size()); - for(unsigned i = 0; i < source.size(); i++) operator[](i) = source.operator[](i); - return *this; - } - - pointer_vector(const pointer_vector &source) : pool(nullptr), poolsize(0), objectsize(0) { - operator=(source); - } - - //move - inline pointer_vector& operator=(pointer_vector &&source) { - reset(); - pool = source.pool; - poolsize = source.poolsize; - objectsize = source.objectsize; - source.pool = nullptr; - source.reset(); - return *this; - } - - pointer_vector(pointer_vector &&source) : pool(nullptr), poolsize(0), objectsize(0) { - operator=(std::move(source)); - } - - //index - inline T& operator[](unsigned index) { - if(index >= objectsize) resize(index + 1); - if(!pool[index]) pool[index] = new T; - return *pool[index]; - } - - inline const T& operator[](unsigned index) const { - if(index >= objectsize || !pool[index]) throw "vector[] out of bounds"; - return *pool[index]; - } - - //iteration - struct iterator { - bool operator!=(const iterator &source) const { return index != source.index; } - T& operator*() { return vector.operator[](index); } - iterator& operator++() { index++; return *this; } - iterator(const pointer_vector &vector, unsigned index) : vector(vector), index(index) {} - private: - const pointer_vector &vector; - unsigned index; - }; - - iterator begin() { return iterator(*this, 0); } - iterator end() { return iterator(*this, objectsize); } - const iterator begin() const { return iterator(*this, 0); } - const iterator end() const { return iterator(*this, objectsize); } - }; -} - -#endif diff --git a/snesfilter/out/.gitignore b/snesfilter/out/.gitignore deleted file mode 100644 index 72e8ffc0..00000000 --- a/snesfilter/out/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/snesshader/Archive/HDR-TV.OpenGL.shader b/snesshader/Archive/HDR-TV.OpenGL.shader deleted file mode 100755 index 929f378a..00000000 --- a/snesshader/Archive/HDR-TV.OpenGL.shader +++ /dev/null @@ -1,17 +0,0 @@ -shader language=GLSL - vertex~ - void main(void) { - gl_Position = ftransform(); - gl_TexCoord[0] = gl_MultiTexCoord0; - } - - fragment~ filter=linear - uniform sampler2D rubyTexture; - - void main(void) { - vec4 rgb = texture2D(rubyTexture, gl_TexCoord[0].xy); - vec4 intens = smoothstep(0.2,0.8,rgb) + normalize(vec4(rgb.xyz, 1.0)); - - if(fract(gl_FragCoord.y * 0.5) > 0.5) intens = rgb * 0.8; - gl_FragColor = intens; - } diff --git a/snesshader/Archive/Watercolor.OpenGL.shader b/snesshader/Archive/Watercolor.OpenGL.shader deleted file mode 100755 index 5bce374e..00000000 --- a/snesshader/Archive/Watercolor.OpenGL.shader +++ /dev/null @@ -1,61 +0,0 @@ -shader language=GLSL - vertex~ - uniform vec2 rubyTextureSize; - - void main() - { - float x = 0.5 * (1.0 / rubyTextureSize.x); - float y = 0.5 * (1.0 / rubyTextureSize.y); - vec2 dg1 = vec2( x, y); - vec2 dg2 = vec2(-x, y); - vec2 dx = vec2(x, 0.0); - vec2 dy = vec2(0.0, y); - - gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_TexCoord[1].xy = gl_TexCoord[0].xy - dg1; - gl_TexCoord[1].zw = gl_TexCoord[0].xy - dy; - gl_TexCoord[2].xy = gl_TexCoord[0].xy - dg2; - gl_TexCoord[2].zw = gl_TexCoord[0].xy + dx; - gl_TexCoord[3].xy = gl_TexCoord[0].xy + dg1; - gl_TexCoord[3].zw = gl_TexCoord[0].xy + dy; - gl_TexCoord[4].xy = gl_TexCoord[0].xy + dg2; - gl_TexCoord[4].zw = gl_TexCoord[0].xy - dx; - } - - fragment~ filter=linear - vec4 compress(vec4 in_color, float threshold, float ratio) - { - vec4 diff = in_color - vec4(threshold); - diff = clamp(diff, 0.0, 100.0); - return in_color - (diff * (1.0 - 1.0/ratio)); - } - - uniform sampler2D rubyTexture; - uniform vec2 rubyTextureSize; - - void main() - { - vec3 c00 = texture2D(rubyTexture, gl_TexCoord[1].xy).xyz; - vec3 c01 = texture2D(rubyTexture, gl_TexCoord[4].zw).xyz; - vec3 c02 = texture2D(rubyTexture, gl_TexCoord[4].xy).xyz; - vec3 c10 = texture2D(rubyTexture, gl_TexCoord[1].zw).xyz; - vec3 c11 = texture2D(rubyTexture, gl_TexCoord[0].xy).xyz; - vec3 c12 = texture2D(rubyTexture, gl_TexCoord[3].zw).xyz; - vec3 c20 = texture2D(rubyTexture, gl_TexCoord[2].xy).xyz; - vec3 c21 = texture2D(rubyTexture, gl_TexCoord[2].zw).xyz; - vec3 c22 = texture2D(rubyTexture, gl_TexCoord[3].xy).xyz; - - vec2 tex = gl_TexCoord[0].xy; - vec2 texsize = rubyTextureSize; - - vec3 first = mix(c00, c20, fract(tex.x * texsize.x + 0.5)); - vec3 second = mix(c02, c22, fract(tex.x * texsize.x + 0.5)); - - vec3 mid_horiz = mix(c01, c21, fract(tex.x * texsize.x + 0.5)); - vec3 mid_vert = mix(c10, c12, fract(tex.y * texsize.y + 0.5)); - - vec3 res = mix(first, second, fract(tex.y * texsize.y + 0.5)); - vec4 final = vec4(0.26 * (res + mid_horiz + mid_vert) + 3.5 * abs(res - mix(mid_horiz, mid_vert, 0.5)), 1.0); - gl_FragColor = compress(final, 0.8, 5.0); - } diff --git a/snesshader/Curvature.OpenGL.shader b/snesshader/Curvature.OpenGL.shader deleted file mode 100755 index 2a7083a5..00000000 --- a/snesshader/Curvature.OpenGL.shader +++ /dev/null @@ -1,22 +0,0 @@ - - - - diff --git a/snesshader/HQ2x.OpenGL.shader b/snesshader/HQ2x.OpenGL.shader deleted file mode 100755 index ef507728..00000000 --- a/snesshader/HQ2x.OpenGL.shader +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - diff --git a/snesshader/Makefile b/snesshader/Makefile deleted file mode 100755 index 5180834a..00000000 --- a/snesshader/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -install: - mkdir -p ~/.config/bsnes/shaders - chmod 777 ~/.config/bsnes/shaders - cp *.shader ~/.config/bsnes/shaders diff --git a/snesshader/Pixellate.OpenGL.shader b/snesshader/Pixellate.OpenGL.shader deleted file mode 100755 index 4ddcae18..00000000 --- a/snesshader/Pixellate.OpenGL.shader +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - diff --git a/snesshader/Scale2x.OpenGL.shader b/snesshader/Scale2x.OpenGL.shader deleted file mode 100755 index cfe0e689..00000000 --- a/snesshader/Scale2x.OpenGL.shader +++ /dev/null @@ -1,55 +0,0 @@ - - - - - = 0.5) { tmp = colB; colB = colH; colH = tmp; } //E1 (or E3): swap B and H - if(sel.x >= 0.5) { tmp = colF; colF = colD; colD = tmp; } //E2 (or E3): swap D and F - - if(colB == colD && colB != colF && colD != colH) { //do the Scale2x rule - col = colD; - } - - gl_FragColor = col; - } - ]]> - diff --git a/snesshader/Sepia.Direct3D.shader b/snesshader/Sepia.Direct3D.shader deleted file mode 100755 index 1fa725e2..00000000 --- a/snesshader/Sepia.Direct3D.shader +++ /dev/null @@ -1,30 +0,0 @@ - - - ; }; - float3 LightColor = { 1.0, 0.7, 0.5 }; - float3 DarkColor = { 0.2, 0.05, 0.0 }; - - float4 DiffColorPass(in float2 Tex : TEXCOORD0) : COLOR0 - { - vec.x = 0.5; - vec.y = 1.0; - float3 scnColor = LightColor * tex2D(s0, Tex).xyz; - float3 grayXfer = float3(0.3, 0.59, 0.11); - float gray = dot(grayXfer, scnColor); - float3 muted = lerp(scnColor, gray.xxx, vec.x); - float3 sepia = lerp(DarkColor, LightColor, gray); - float3 result = lerp(muted, sepia, vec.y); - return float4(result, 1); - } - - Technique T0 - { - pass p0 { PixelShader = compile ps_2_0 DiffColorPass(); } - } - ]]> -