Compare commits

..

12 Commits
v031 ... v033

Author SHA1 Message Date
byuu
9133129209 Update to bsnes v033 release.
This release adds SPC7110 emulation, without the need for graphics packs!!, and a rewritten S-RTC (real-time clock) emulator.
SPC7110 support means that Far East of Eden Zero, FEoEZ: Shounen Jump Edition, Momotarou Dentetsu Happy and Super Power League 4 are now all fully playable. I will warn you, the emulation is very slow in this version -- while most areas of each game will run at the same speed as other games, there are a few peak moments where speed will drop by up to ~50%. The reason for the slow-down is that I am currently uncertain how to determine the amount of data to decompress in advance, so I default to the maximum amount possible. The reason I am releasing now anyway, is because I beleive in the "release early, release often" paradigm. It will likely take me a few weeks to finish researching this chip, and I didn't want to keep the work I had private during that time. But rest assured, bsnes v034 should feature much faster SPC7110 emulation.
neviksti, Andreas Naive and jolly_codger worked non-stop on the SPC7110 decompression algorithm for the past two weeks. caitsith2 provided valuable data to the effort. I only wish that I could've been of some use, but alas, I had no role in this. In the end, it was neviksti who managed to crack all three(!!) compression modes of this chip, which turned out to be a customized 8-bit QM-coder with a prediction model. You can read more about this here. I would also like to thank Dark Force and John Weidman (aka The Dumper) for their research notes on the SPC7110 register interface.
For those who don't understand the hoopla about figuring out this compression algorithm when we already had graphics pack simulation, I should note that we have since found a few errors in these packs. Not to mention, you no longer need ~4-16MB packs for each game you wish to run. They work like any other game now. Better still, the chip can now be used to compress new graphics, eg for any future translation efforts on these titles.
The real-time clocks in both Far East of Eden Zero and Dai Kaijuu Monogatari 2 will now save a ".rtc" file in your save folder, which contains the clock as set by the video game, as well as a timestamp from your computer when the time was last updated. It uses the difference between the saved timestamp and current time to update the time. This allows you to specify any time you like, whereas previously bsnes would just use your computer's current time, ignoring the time you set in-game. It also allows the "round clock by 30 seconds" option in both games to work. I avoided this before because this method makes supporting daylight savings time and such impractical, although I should note that the original hardware did not support DST, either. This method was required to pass the SPC7110 tests, and is overall much more faithful to how the original chips worked.
Once again, I'd really like to personally thank neviksti for his tireless efforts. Eliminating graphics packs from SNES emulation was one of my primary reasons for getting involved in the SNES emulation scene. That neviksti managed to crack this algorithm means a lot to me. Thank you so much, neviksti. This release is dedicated to you, now go get some sleep Wink
2008-07-20 00:06:28 +00:00
byuu
7d83cde40a Update to bsnes v032r01? release.
This worked great, thank you. libao is now tolerable on ALSA. Now I
just need to add support for disabling "Audio::Synchronize" (by
disabling sound output, since libao is a blocking API.)

---

EDIT: posted a new WIP, with RedDwarf's ALSA and libao fixes. Both
work very well for me, your mileage may vary.

No Windows binary, as it would be exactly the same as v032a, anyway.
This one's mainly for Linux users who can compile from source.

[No archive available]
2008-06-02 02:00:00 +00:00
byuu
bbc77a6cf2 Update to bsnes v032a release.
- Windows: file open filters are now working once again
    - All ports: emulation speed setting is now properly restored at startup
2008-05-26 08:46:05 +00:00
byuu
ebb9367c68 Update to bsnes v032 release.
- Core: simplified CPU / SMP flag calculations
    - Added ALSA audio output driver to Linux port [Nach]
    - Improved font handling for Windows and Linux ports
    - Greatly cleaned up the user interface
    - Windows port now uses Unicode instead of ANSI
    - Added localization support
    - Config and locale files can now be placed inside bsnes executable directory for single-user mode, if desired
    - Fixed crashing bug with HQ2x on Linux/amd64 port [RedDwarf, Nach]
    - Hid "Power Cycle" option by default, as it is too similar to "Reset"
    - Slighty tweaked program icon [FitzRoy]
    - Minor code cleanups -- replaced union bitfields with templates, improved memory allocation, etc
2008-05-25 18:45:59 +00:00
byuu
96fe8f760d Update to bsnes v031r08? release.
Thank you everyone for the translations! I've also posted a new WIP,
with an improved Japanese locale. No changes to the strings that
anyone has to worry about with theirs.

To strike a compromise, I've removed power cycle from the menu by
default, and added a new config file option, "advanced.enable". Set to
false initially, but if you set it to true and restart, power cycle
will re-appear. I intend to use this option to hide the debugger
functionality if and when that gets re-added, as well. Plus we can
remove other questionably useful / confusing stuff this way. The key
binding for it still shows up (removing it there would be tricky), but
it's not bound to anything by default, either. Sound fair?

Also, something I've been meaning to do for a while now ...
unload/reset/power cycle are now disabled when a cartridge is not
loaded.

[No archive available]
2008-05-22 09:18:00 +00:00
byuu
8abd1b2dfe Update to bsnes v031r07? release.
Okay, new WIP. Couple of changes.

One, I was displaying the warning message about unsupported chips no
matter what. Oops, fixed.

Two, removed the "Select Folder" text. The dialog looks a bit empty
now, but oh well.

Three, added "Ok" to the warning message box strings.

Four, added "Enabled" to the cheat editor strings. You'll notice that
"Disabled" is not there -- it's shared by the speed regulation
setting. I know, sharing strings sucks, but that's pretty much how the
localization system works, sorry. You can use something simple like
"On" / "Off" in place of "Enabled" / "Disabled", if necessary.

Also updated the locale.cfg file for everyone:
http://byuu.cinnamonpirate.com/temp/locale.cfg

[No archive available]
2008-05-20 07:02:00 +00:00
byuu
f6efcbe6fd Update to bsnes v031r06? release.
Okay, I've posted a new WIP, which has a completed locale.cfg file.
Well, it's completed for v032, at least. All translations are going to
have to be updated for every release, sadly.

For those interested in translating it, I'm looking to only have
native speakers perform translations. I don't care if things aren't a
perfect literal translation, so long as the general idea gets across.
But I don't want anyone using machine translation tools, either.
They're very unprofessional, better to wait until someone fluent comes
along. Yes, I know that's ironic given my translation to Japanese:
hoping someone will re-do that one.

The reference locale file is here:
http://byuu.cinnamonpirate.com/temp/locale.cfg

Format is obviously UTF-8. Yours will need to be in this format as
well. Any local encodings will fail miserably.

You can see most of the options in bsnes v031 to see where they come
into play. I have them mostly sorted per window. Some windows share
the same string. I doubt that's going to be a problem, but we'll see.

If you have access to the WIPs, be sure to get the latest one to test
with. If not, and you're willing to translate the UI, feel free to PM
me and I'll happily send you a link to it.

I've added a "Localization by:" field to the about screen. Please feel
free to add your name there.

Next up, I'm trying something a bit different for the config files,
and I've updated readme.txt to reflect this:

bsnes will now check in the same folder as the executable for
bsnes.cfg and locale.cfg. If they're found, bsnes will use these
files. If they are not found, it will use your user profile folder for
storage.

So, if you want bsnes to run in single-user mode, just make sure
bsnes.cfg and/or locale.cfg exist. If not, you can create a blank file
and bsnes will use that next time you run it. If you want multi-user
mode, delete the files. If you want multiple profiles, use single-user
mode and multiple copies of the executable.

I'll be distributing future Windows binaries with blank bsnes.cfg and
locale.cfg files, so that single-user mode is the default. Just delete
them to switch to the old method if you prefer. Hopefully this pleases
everyone.

[No archive available]
2008-05-19 08:48:00 +00:00
byuu
36859ea52c Update to bsnes v031r05? release.
Well, that was certainly a pain in the ass ...

Image

Had to port hiro to full-on Unicode / UTF-16. But the GUI API still
takes UTF-8, it's all converted internally now, bidirectionally.

Oh, and don't make fun of my Japanese :P

---

As for the new WIP, I've included my example locale.cfg. No other
lines will translate, so don't try yet. You need to put it in the
.bsnes folder next to bsnes.cfg. And don't try it unless you have
Japanese fonts, obviously.

[No archive available]
2008-05-15 07:51:00 +00:00
byuu
64589148d4 Update to bsnes v031r04? release.
New WIP.

This one adds DPI-independent font sizing for both Windows and Linux.
With that, I've reduced the font size back down to "Tahoma 8" on
Windows, and "Sans 8" on Linux.

Because of that, I was able to reduce textbox and button height from
30 to 25, and label, checkbox and radiobox height from 20 to 18. In
other words, the UI looks like it did back with v019.

There's only one tiny flaw with the Linux port, I'm unable to change
the font face for the listbox column header. It's not actually a
widget, so it ignores my gtk_container_foreach ->
gtk_widget_modify_font() calls. Any help would be greatly appreciated.

I've also added FitzRoy's new icon. It seems to only have 32-bit
icons, and no 256-color icons ... I guess we'll see how that looks on
Win2k soon enough.

Lastly, statusbar toggle was broken in the last WIP, that's fixed now.

[No archive available]
2008-05-12 05:26:00 +00:00
byuu
89ae1101ee Update to bsnes v031r03? release.
Another WIP. This one changes the GUI toolkit to not invoke callbacks
when the API is used to set the state of widgets. With that it was
really easy to get the speedreg / frameskip checks to update when
using the keyboard controls.

What I really need for this WIP is testing to see if any UI elements
are now broken as a result of the change. For example, try and get a
checkbox to not represent the actual state of something. Eg a
frameskip of 2 but the checkbox is on 0. Also check startup states and
that sort of thing.

The UI code really needs to be cleaned up at this point ...

[No archive available]
2008-05-07 06:30:00 +00:00
byuu
340d86845a Update to bsnes v031r02? release.
New WIP. Please be sure to test a few games with this one to look for
regressions.

I got tired of using bit packing for CPU / SMP register flags, because
they do not mask the upper bits properly.

In other words, (assume big endian) if you have struct { uint8_t n:1,
v:1, m:1, x:1, d:1, i:1, z:1, c:1; } p; and you set p.m = 7; it will
set p.v and p.n as well. It doesn't cast the type to bool.

So I rewrote the old template struct trick, but bound it with a
reference rather than relying upon union alignment. Looks something
like this:

    template<int mask>
    struct CPUFlag {
      uint8 &data;

      inline operator bool() const { return data & mask; }
      inline CPUFlag& operator=(bool i) { data = (data & ~mask) | (-i
    & mask); return *this; }

      CPUFlag(uint8 &data_) : data(data_) {}
    };

    class CPURegFlags {

    public:
      uint8 data;
      CPUFlag<0x80> n;
      CPUFlag<0x40> v;
    ...
      CPURegFlags() : data(0), n(data), v(data), m(data), x(data),
    d(data), i(data), z(data), c(data) {}

    };


Surprisingly, benchmarks show this method is ~2x faster, but flags
were never a bottleneck so it won't affect bsnes' speed.

Anyway, with this, I decided to get rid of the confusing and stupid
!!() stuff all throughout the CMP and SMP opfn.cpp files. It's no
longer needed since the template assignment takes only a boolean
argument. Anything not zero becomes one with that.

So code such as this:

    uint8 sSMP::op_adc(uint8 x, uint8 y) {
    int16 r = x + y + regs.p.c;
      regs.p.n = !!(r & 0x80);
      regs.p.v = !!(~(x ^ y) & (y ^ (uint8)r) & 0x80);
      regs.p.h = !!((x ^ y ^ (uint8)r) & 0x10);
      regs.p.z = ((uint8)r == 0);
      regs.p.c = (r > 0xff);
      return r;
    }


Now looks like this:

    uint8 sSMP::op_adc(uint8 x, uint8 y) {
      int r = x + y + regs.p.c;
      regs.p.n = r & 0x80;
      regs.p.v = ~(x ^ y) & (x ^ r) & 0x80;
      regs.p.h = (x ^ y ^ r) & 0x10;
      regs.p.z = (uint8)r == 0;
      regs.p.c = r > 0xff;
      return r;
    }


I also took the time to figure out how the hell the overflow stuff
worked. Pretty neat stuff.

Essentially, overflow is set when you add/subtract two positive or two
negative numbers, and the result ends up with a different sign. Hence,
the sign overflowed, so your negative number is now positive, or vice
versa.

A simple way to simulate it is:
int result = (int8_t)x + (int8_t)y;
bool overflow = (result < -128 || result > 127);

But there's no reason to perform signed math, since the result can't
be used for anything else, not even any other flags, as the opcode
math is always unsigned.

So to implement it with this:
int result = (uint8_t)x + (uint8_t)y;

We just verify that both signs in x and y are the same, and that their
sign is different from the result to set overflow, eg:
bool overflow = (x & 0x80) == (y & 0x80) && (x & 0x80) != (result &
0x80);

But that's kind of slow. We can test a single bit for equality and
merge the &0x80's by using a XOR table:
0^0=0, 0^1=1, 1^0=1, 1^1=0
The trick here is that if the two bits are equal, we get 0, if they
are not equal, we get one.

So if we want to see if x&0x80 == y&0x80, we can do:
!((x ^ y) & 0x80);

... or we can simply invert the XOR result so that 1 = equal, 0 =
different, eg ~(x ^ y) & 0x80;

The latter is nice because it keeps the bit positions in-tact. Whereas
the former reduces to 1 or 0, the latter remains 0x80 or 0x00. This is
good for chaining, as I'll demonstrate below.

Do the same for the second test and we get:
bool overflow = ~(x ^ y) & 0x80 && (x ^ result) & 0x80;

We complement the former because we want to verify they are the same,
we don't for the latter because we want to verify that they have
changed.

Now we can basically use one more trick to combine the two bit masks
here. We want to return 1 when overflow is set, so we can look for a
pattern that will only return one when both the first and second tests
pass.

An AND table works great here. 0&0=0, 0&1=0, 1&0=0, 1&1=1. Only if
both are true do we end up with 1.

So this means we can AND the two results, and then mask the only bit
we care about once to get the result, eg:
bool overflow = ~(x ^ y) & (x ^ result) & 0x80;

And there we go, that's where that bizarre math trick comes from. I
realized while doing this something that bugged me in the past.

I used to think that for some reason, the S-SMP add overflow test
required x^y & y^r, whereas S-CPU add overflow used x^y & x^r.
Probably because I read the algorithm from Snes9x's sources or
something.

But that was flawed -- since addition is commutative, it doesn't
matter whether the latter is x^result or y^result. Only in subtraction
does the order matter, where you must always use x^result to test the
initial value every time.

Subtraction switches up things a little. It sets overflow only when
the signs of x and y are _different_, and when x and the result are
also different, eg:
bool overflow = (x ^ y) & (x ^ result) & 0x80;

Fun stuff, huh?

So I was wanting this tested thoroughly, just in case there was a typo
or something when updating the opfn.cpp files.

---

That said, I also polished up the UI a bit. Moved disabled to the
bottom of the speed regulation list, and added key / joypad bindings
for "exit emulator", "speed regulation increase / decrease" and
"frameskip increase / decrease".

I know these key bindings do not update the menubar radiobox positions
yet. I'll get that taken care of shortly.

[No archive available]
2008-04-19 12:03:00 +00:00
byuu
b895f29bed Update to bsnes v031r01? release.
New WIP posted.

Not much to this one.

- added FitzRoy's updated program icon
- removed safe_free / safe_delete / safe_release template functions
- replaced nearly all malloc / free calls with new / delete[]

And lastly ... long ago, I used "File / Edit / Help" to conform to
standard UI design. I quickly replaced Edit with Settings, and later
Help with Misc. Lately, the last one has been bugging me ... "File"?
File what? Why is there a reset system option under file?

So, it may be somewhat controversial, but I renamed File to System,
and dropped the now superfluous " System" from Reset / Power Cycle.

I'd honestly like to remove "Exit" from that menu as well, but I know
I'd be pushing it then.

What I want to do next is move "Disabled" in speed regulation to the
bottom of the list, and add key bindings to increase / decrease speed
regulation. I'd like the step after fastest to be disabled. It makes
sense, as fastest can never be faster than disabled, but disabled can
be faster than fastest.

Other nice ideas would be: a cartridge info option under the system
menu somewhere, frameskip +/- key bindings, an exit emulator key
binding, a new GUI panel with options to warn on reset / unload /
exit, and cleaning up of the event namespace for the UI. Specifically,
start working on a more advanced status panel that can display five-
second alerts that override the normal output.

[No archive available]
2008-04-16 12:59:00 +00:00
116 changed files with 3753 additions and 1537 deletions

View File

@@ -66,7 +66,8 @@ such software.
libco, author: byuu
libui, author: byuu
OBC-1 emu, author: byuu
S-DD1 emu, author: Andreas Naive
S-DD1 decompressor, author: Andreas Naive
SPC7110 decompressor, author: neviksti
S-RTC emu, author: byuu
Any software listed above as exemptions may be relicensed individually from

View File

@@ -1,10 +1,10 @@
bsnes
Version: 0.031
Version: 0.033
Author: byuu
--------
========
General:
--------
========
bsnes is a Super Nintendo / Super Famicom emulator that began on
October 14th, 2004.
@@ -13,9 +13,32 @@ http://byuu.org/
Please see license.txt for important licensing information.
------------------
==============
Configuration:
==============
bsnes has two configuration files: bsnes.cfg, for program settings; and
locale.cfg, for localization.
For each file, bsnes will start by looking inside the same folder where the
bsnes executable is located. If said file is not found, it will then check your
user profile folder. On Windows, this is located at "%APPDATA%/.bsnes". On all
other operating systems, this is located at "~/.bsnes". If said file is still
not found, it will automatically be created in your user profile folder.
If you wish to use bsnes in single-user mode, be sure that both files exist
inside the same folder as the bsnes executable. If they do not, you can simply
create new blank files and bsnes will use them in the future.
If you wish to use bsnes in multi-user mode, simply delete these two files from
the bsnes executable directory if they exist.
If you wish to have multiple configuration profiles for the same user, you will
need to make copies of the bsnes executable, and use each one in single-user
mode.
==================
Known Limitations:
------------------
==================
S-CPU
- Multiply / divide register delays not implemented
@@ -33,9 +56,9 @@ Hardware Bugs
- S-CPU.r1 HDMA crashing bug not emulated
- S-CPU<>S-SMP communication bus conflicts not emulated
---------------------
=====================
Unsupported Hardware:
---------------------
=====================
SA-1
Coprocessor used in many popular games, including:
- Dragon Ball Z Hyper Dimension
@@ -52,25 +75,18 @@ Coprocessor used in many popular games, including:
- Star Fox 2 (unreleased beta)
- Super Mario World 2: Yoshi's Island
SPC7110
Coprocessor used only by the following games:
- Far East of Eden Zero
- Far East of Eden Zero: Shounen Jump no Shou
- Momotarou Densetsu Happy
- Super Power League 4
ST-011
SETA DSP used only by Quick-move Shogi Match with Nidan Rank-holder Morita
SETA DSP used by Quick-move Shogi Match with Nidan Rank-holder Morita
ST-018
SETA RISC CPU used only by Quick-move Shogi Match with Nidan Rank-holder Morita 2
SETA RISC CPU used by Quick-move Shogi Match with Nidan Rank-holder Morita 2
Super Gameboy
Cartridge passthrough used for playing Gameboy games
------------------------
========================
Unsupported Controllers:
------------------------
========================
Mouse
Super Scope
Justifier

View File

@@ -11,7 +11,7 @@ ifneq ($(findstring gcc,$(compiler)),) # GCC family
cpp = $(subst cc,++,$(compiler)) $(flags)
obj = o
rule = -c $< -o $@
link =
link = -s
mkbin = -o$1
mkdef = -D$1
mklib = -l$1
@@ -34,7 +34,7 @@ endif
##########
ifeq ($(platform),x) # X11
ruby = video.glx video.xv video.sdl audio.openal audio.oss audio.ao input.sdl input.x
ruby = video.glx video.xv video.sdl audio.openal audio.oss audio.alsa audio.ao input.sdl input.x
link += `pkg-config --libs gtk+-2.0`
link += $(call mklib,Xtst)
delete = rm -f $1
@@ -66,6 +66,7 @@ link += $(if $(findstring video.directdraw,$(ruby)),$(call mklib,ddraw))
link += $(if $(findstring video.glx,$(ruby)),$(call mklib,GL))
link += $(if $(findstring video.wgl,$(ruby)),$(call mklib,opengl32))
link += $(if $(findstring video.xv,$(ruby)),$(call mklib,Xv))
link += $(if $(findstring audio.alsa,$(ruby)),$(call mklib,asound))
link += $(if $(findstring audio.ao,$(ruby)),$(call mklib,ao))
link += $(if $(findstring audio.directsound,$(ruby)),$(call mklib,dsound))
link += $(if $(findstring audio.openal,$(ruby)),$(if $(call streq,$(platform),x),$(call mklib,openal),$(call mklib,openal32)))
@@ -78,7 +79,7 @@ link += $(if $(findstring input.sdl,$(ruby)),`sdl-config --libs`)
objects = main libco hiro ruby libfilter string reader cart cheat \
memory smemory cpu scpu smp ssmp sdsp ppu bppu snes \
bsx srtc sdd1 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010
bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010
ifeq ($(enable_gzip),true)
objects += adler32 compress crc32 deflate gzio inffast inflate inftrees ioapi trees unzip zip zutil
@@ -195,16 +196,17 @@ obj/snes.$(obj): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/*
### special chips ###
#####################
obj/bsx.$(obj) : chip/bsx/bsx.cpp chip/bsx/*
obj/srtc.$(obj) : chip/srtc/srtc.cpp chip/srtc/*
obj/sdd1.$(obj) : chip/sdd1/sdd1.cpp chip/sdd1/*
obj/cx4.$(obj) : chip/cx4/cx4.cpp chip/cx4/*
obj/dsp1.$(obj) : chip/dsp1/dsp1.cpp chip/dsp1/*
obj/dsp2.$(obj) : chip/dsp2/dsp2.cpp chip/dsp2/*
obj/dsp3.$(obj) : chip/dsp3/dsp3.cpp chip/dsp3/*
obj/dsp4.$(obj) : chip/dsp4/dsp4.cpp chip/dsp4/*
obj/obc1.$(obj) : chip/obc1/obc1.cpp chip/obc1/*
obj/st010.$(obj): chip/st010/st010.cpp chip/st010/*
obj/bsx.$(obj) : chip/bsx/bsx.cpp chip/bsx/*
obj/srtc.$(obj) : chip/srtc/srtc.cpp chip/srtc/*
obj/sdd1.$(obj) : chip/sdd1/sdd1.cpp chip/sdd1/*
obj/spc7110.$(obj): chip/spc7110/spc7110.cpp chip/spc7110/*
obj/cx4.$(obj) : chip/cx4/cx4.cpp chip/cx4/*
obj/dsp1.$(obj) : chip/dsp1/dsp1.cpp chip/dsp1/*
obj/dsp2.$(obj) : chip/dsp2/dsp2.cpp chip/dsp2/*
obj/dsp3.$(obj) : chip/dsp3/dsp3.cpp chip/dsp3/*
obj/dsp4.$(obj) : chip/dsp4/dsp4.cpp chip/dsp4/*
obj/obc1.$(obj) : chip/obc1/obc1.cpp chip/obc1/*
obj/st010.$(obj) : chip/st010/st010.cpp chip/st010/*
############
### zlib ###

View File

@@ -1,4 +1,4 @@
#define BSNES_VERSION "0.031"
#define BSNES_VERSION "0.033"
#define BSNES_TITLE "bsnes v" BSNES_VERSION
#define BUSCORE sBus

View File

@@ -13,7 +13,7 @@
#include "cart_header.cpp"
namespace memory {
MappedRAM cartrom, cartram;
MappedRAM cartrom, cartram, cartrtc;
MappedRAM bscram;
MappedRAM stArom, stAram;
MappedRAM stBrom, stBram;
@@ -27,12 +27,12 @@ Cartridge::Region Cartridge::region() { return info.region; }
bool Cartridge::loaded() { return cart.loaded; }
void Cartridge::load_begin(CartridgeType cart_type) {
cart.rom = cart.ram = 0;
cart.rom = cart.ram = cart.rtc = 0;
bs.ram = 0;
stA.rom = stA.ram = 0;
stB.rom = stB.ram = 0;
cart.rom_size = cart.ram_size = 0;
cart.rom_size = cart.ram_size = cart.rtc_size = 0;
bs.ram_size = 0;
stA.rom_size = stA.ram_size = 0;
stB.rom_size = stB.ram_size = 0;
@@ -44,20 +44,21 @@ void Cartridge::load_begin(CartridgeType cart_type) {
info.bsxflash = false;
info.st = false;
info.superfx = false;
info.sa1 = false;
info.spc7110 = false;
info.srtc = false;
info.sdd1 = false;
info.cx4 = false;
info.dsp1 = false;
info.dsp2 = false;
info.dsp3 = false;
info.dsp4 = false;
info.obc1 = false;
info.st010 = false;
info.st011 = false;
info.st018 = false;
info.superfx = false;
info.sa1 = false;
info.srtc = false;
info.sdd1 = false;
info.spc7110 = false;
info.spc7110rtc = false;
info.cx4 = false;
info.dsp1 = false;
info.dsp2 = false;
info.dsp3 = false;
info.dsp4 = false;
info.obc1 = false;
info.st010 = false;
info.st011 = false;
info.st018 = false;
info.dsp1_mapper = DSP1Unmapped;
@@ -73,6 +74,7 @@ void Cartridge::load_begin(CartridgeType cart_type) {
void Cartridge::load_end() {
memory::cartrom.map(cart.rom, cart.rom_size);
memory::cartram.map(cart.ram, cart.ram_size);
memory::cartrtc.map(cart.rtc, cart.rtc_size);
memory::bscram.map(bs.ram, bs.ram_size);
memory::stArom.map(stA.rom, stA.rom_size);
memory::stAram.map(stA.ram, stA.ram_size);
@@ -102,19 +104,20 @@ bool Cartridge::unload() {
bus.unload_cart();
switch(info.type) {
case CartridgeNormal: unload_cart_normal(); break;
case CartridgeBSX: unload_cart_bsx(); break;
case CartridgeBSC: unload_cart_bsc(); break;
case CartridgeSufamiTurbo: unload_cart_st(); break;
case CartridgeNormal: unload_cart_normal(); break;
case CartridgeBSX: unload_cart_bsx(); break;
case CartridgeBSC: unload_cart_bsc(); break;
case CartridgeSufamiTurbo: unload_cart_st(); break;
}
safe_free(cart.rom);
safe_free(cart.ram);
safe_free(bs.ram);
safe_free(stA.rom);
safe_free(stA.ram);
safe_free(stB.rom);
safe_free(stB.ram);
if(cart.rom) { delete[] cart.rom; cart.rom = 0; }
if(cart.ram) { delete[] cart.ram; cart.ram = 0; }
if(cart.rtc) { delete[] cart.rtc; cart.rtc = 0; }
if(bs.ram) { delete[] bs.ram; bs.ram = 0; }
if(stA.rom) { delete[] stA.rom; stA.rom = 0; }
if(stA.ram) { delete[] stA.ram; stA.ram = 0; }
if(stB.rom) { delete[] stB.rom; stB.rom = 0; }
if(stB.ram) { delete[] stB.ram; stB.ram = 0; }
char fn[PATH_MAX];
strcpy(fn, cart.fn);

View File

@@ -32,6 +32,7 @@ public:
HiROM,
ExLoROM,
ExHiROM,
SPC7110ROM,
BSXROM,
BSCLoROM,
BSCHiROM,
@@ -48,8 +49,8 @@ public:
struct {
bool loaded;
char fn[PATH_MAX];
uint8 *rom, *ram;
uint rom_size, ram_size;
uint8 *rom, *ram, *rtc;
uint rom_size, ram_size, rtc_size;
} cart;
struct {
@@ -85,6 +86,7 @@ public:
bool srtc;
bool sdd1;
bool spc7110;
bool spc7110rtc;
bool cx4;
bool dsp1;
bool dsp2;
@@ -142,12 +144,13 @@ public:
private:
char patchfn[PATH_MAX];
char savefn[PATH_MAX];
char savefn[PATH_MAX];
char rtcfn[PATH_MAX];
char cheatfn[PATH_MAX];
};
namespace memory {
extern MappedRAM cartrom, cartram;
extern MappedRAM cartrom, cartram, cartrtc;
extern MappedRAM bscram;
extern MappedRAM stArom, stAram;
extern MappedRAM stBrom, stBram;

View File

@@ -14,7 +14,7 @@ void Cartridge::load_cart_bsc(const char *base, const char *slot) {
if(load_file(get_patch_filename(cart.fn, "ups"), data, size, CompressionInspect) == true) {
apply_patch(data, size, cart.rom, cart.rom_size);
if(data) { free(data); data = 0; }
delete[] data;
}
if(*bs.fn) {
@@ -23,7 +23,7 @@ void Cartridge::load_cart_bsc(const char *base, const char *slot) {
bs.ram = data, bs.ram_size = size;
if(load_file(get_patch_filename(bs.fn, "ups"), data, size, CompressionInspect) == true) {
apply_patch(data, size, bs.ram, bs.ram_size);
if(data) { free(data); data = 0; }
delete[] data;
}
}
}
@@ -35,12 +35,12 @@ void Cartridge::load_cart_bsc(const char *base, const char *slot) {
info.region = NTSC;
if(info.ram_size > 0) {
cart.ram = (uint8*)malloc(cart.ram_size = info.ram_size);
cart.ram = new uint8_t[cart.ram_size = info.ram_size];
memset(cart.ram, 0xff, cart.ram_size);
if(load_file(get_save_filename(cart.fn, "srm"), data, size, CompressionNone) == true) {
memcpy(cart.ram, data, min(size, cart.ram_size));
safe_free(data);
delete[] data;
}
}

View File

@@ -20,7 +20,7 @@ void Cartridge::load_cart_bsx(const char *base, const char *slot) {
if(load_file(get_patch_filename(cart.fn, "ups"), data, size, CompressionInspect) == true) {
apply_patch(data, size, cart.rom, cart.rom_size);
if(data) { free(data); data = 0; }
delete[] data;
}
memset(bsxcart.sram.handle (), 0x00, bsxcart.sram.size ());
@@ -28,12 +28,12 @@ void Cartridge::load_cart_bsx(const char *base, const char *slot) {
if(load_file(get_save_filename(cart.fn, "srm"), data, size, CompressionNone) == true) {
memcpy(bsxcart.sram.handle (), data, min(bsxcart.sram.size (), size));
safe_free(data);
delete[] data;
}
if(load_file(get_save_filename(cart.fn, "psr"), data, size, CompressionNone) == true) {
memcpy(bsxcart.psram.handle(), data, min(bsxcart.psram.size(), size));
safe_free(data);
delete[] data;
}
if(*bs.fn) {
@@ -42,7 +42,7 @@ void Cartridge::load_cart_bsx(const char *base, const char *slot) {
bs.ram = data, bs.ram_size = size;
if(load_file(get_patch_filename(bs.fn, "ups"), data, size, CompressionInspect) == true) {
apply_patch(data, size, bs.ram, bs.ram_size);
if(data) { free(data); data = 0; }
delete[] data;
}
}
}

View File

@@ -158,8 +158,8 @@ bool Cartridge::apply_patch(const uint8_t *pdata, const unsigned psize, uint8_t
}
if(apply == true) {
free(data);
data = (uint8_t*)malloc(size = outsize);
delete[] data;
data = new uint8_t[size = outsize];
memcpy(data, outdata, outsize);
} else {
dprintf("* Warning: patch application failed!");
@@ -168,11 +168,12 @@ bool Cartridge::apply_patch(const uint8_t *pdata, const unsigned psize, uint8_t
if(outdata) delete[] outdata;
}
bool Cartridge::save_file(const char *fn, uint8 *data, uint size) {
FileWriter ff(fn);
if(!ff.ready())return false;
ff.write(data, size);
return true;
bool Cartridge::save_file(const char *fn, uint8 *data, uint size) {
FILE *fp = fopen(fn, "wb");
if(!fp) return false;
fwrite(data, 1, size, fp);
fclose(fp);
return true;
}
#endif //ifdef CART_CPP

View File

@@ -52,8 +52,9 @@ void Cartridge::read_header() {
}
if(mapper == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
//rom_type: 0xf5 = no S-RTC, 0xf9 = S-RTC
info.spc7110 = true;
info.spc7110rtc = (rom_type == 0xf9);
info.mapper = SPC7110ROM;
}
if(mapper == 0x20 && rom_type == 0xf3) {
@@ -179,7 +180,7 @@ void Cartridge::find_header() {
score_ex = 0;
} else {
if(rom[0x7fc0 + MAPPER] == 0x32) score_lo++;
else score_ex += 16;
else score_ex += 12;
}
if(score_lo >= score_hi && score_lo >= score_ex) {

View File

@@ -12,17 +12,17 @@ void Cartridge::load_cart_normal(const char *filename) {
//load ROM data, ignore 512-byte header if detected
if((size & 0x7fff) != 512) {
cart.rom = (uint8*)malloc(cart.rom_size = size);
cart.rom = new uint8_t[cart.rom_size = size];
memcpy(cart.rom, data, size);
} else {
cart.rom = (uint8*)malloc(cart.rom_size = size - 512);
cart.rom = new uint8_t[cart.rom_size = size - 512];
memcpy(cart.rom, data + 512, size - 512);
}
safe_free(data);
delete[] data;
if(load_file(get_patch_filename(cart.fn, "ups"), data, size, CompressionInspect) == true) {
apply_patch(data, size, cart.rom, cart.rom_size);
if(data) { free(data); data = 0; }
delete[] data;
}
info.crc32 = crc32_calculate(cart.rom, cart.rom_size);
@@ -31,12 +31,20 @@ void Cartridge::load_cart_normal(const char *filename) {
read_header();
if(info.ram_size > 0) {
cart.ram = (uint8*)malloc(cart.ram_size = info.ram_size);
cart.ram = new uint8_t[cart.ram_size = info.ram_size];
memset(cart.ram, 0xff, cart.ram_size);
if(load_file(get_save_filename(cart.fn, "srm"), data, size, CompressionNone) == true) {
memcpy(cart.ram, data, min(size, cart.ram_size));
safe_free(data);
delete[] data;
}
}
if(info.srtc || info.spc7110rtc) {
cart.rtc = new(zeromemory) uint8_t[cart.rtc_size = 20];
if(load_file(get_save_filename(cart.fn, "rtc"), data, size, CompressionNone) == true) {
memcpy(cart.rtc, data, min(size, cart.rtc_size));
delete[] data;
}
}
@@ -49,6 +57,7 @@ void Cartridge::load_cart_normal(const char *filename) {
void Cartridge::unload_cart_normal() {
if(cart.ram) save_file(get_save_filename(cart.fn, "srm"), cart.ram, cart.ram_size);
if(cart.rtc) save_file(get_save_filename(cart.fn, "rtc"), cart.rtc, cart.rtc_size);
}
#endif //ifdef CART_CPP

View File

@@ -15,51 +15,51 @@ void Cartridge::load_cart_st(const char *base, const char *slotA, const char *sl
uint8_t *data = 0;
unsigned size;
if(load_file(cart.fn, data, size, CompressionAuto) == true) {
cart.rom = (uint8*)malloc(cart.rom_size = 0x040000);
cart.rom = new(zeromemory) uint8_t[cart.rom_size = 0x040000];
memcpy(cart.rom, data, min(size, cart.rom_size));
safe_free(data);
delete[] data;
if(load_file(get_patch_filename(cart.fn, "ups"), data, size, CompressionInspect) == true) {
apply_patch(data, size, cart.rom, cart.rom_size);
if(data) { free(data); data = 0; }
delete[] data;
}
}
if(*stA.fn) {
if(load_file(stA.fn, data, size, CompressionAuto) == true) {
stA.rom = (uint8*)malloc(stA.rom_size = 0x100000);
stA.rom = new(zeromemory) uint8_t[stA.rom_size = 0x100000];
memcpy(stA.rom, data, min(size, stA.rom_size));
safe_free(data);
delete[] data;
if(load_file(get_patch_filename(stA.fn, "ups"), data, size, CompressionInspect) == true) {
apply_patch(data, size, stA.rom, stA.rom_size);
if(data) { free(data); data = 0; }
delete[] data;
}
stA.ram = (uint8*)malloc(stA.ram_size = 0x020000);
stA.ram = new uint8_t[stA.ram_size = 0x020000];
memset(stA.ram, 0xff, stA.ram_size);
if(load_file(get_save_filename(stA.fn, "srm"), data, size, CompressionNone) == true) {
memcpy(stA.ram, data, min(size, 0x020000U));
safe_free(data);
delete[] data;
}
}
}
if(*stB.fn) {
if(load_file(stB.fn, data, size, CompressionAuto) == true) {
stB.rom = (uint8*)malloc(stB.rom_size = 0x100000);
stB.rom = new(zeromemory) uint8_t[stB.rom_size = 0x100000];
memcpy(stB.rom, data, min(size, stB.rom_size));
safe_free(data);
delete[] data;
if(load_file(get_patch_filename(stB.fn, "ups"), data, size, CompressionInspect) == true) {
apply_patch(data, size, stB.rom, stB.rom_size);
if(data) { free(data); data = 0; }
delete[] data;
}
stB.ram = (uint8*)malloc(stB.ram_size = 0x020000);
stB.ram = new uint8_t[stB.ram_size = 0x020000];
memset(stB.ram, 0xff, stB.ram_size);
if(load_file(get_save_filename(stB.fn, "srm"), data, size, CompressionNone) == true) {
memcpy(stB.ram, data, min(size, 0x020000U));
safe_free(data);
delete[] data;
}
}
}

View File

@@ -20,7 +20,7 @@ void BSXCart::reset() {
}
void BSXCart::update_memory_map() {
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)psram;
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)psram;
if((regs.r[0x02] & 0x80) == 0x00) { //LoROM mapping
bus.map(Bus::MapLinear, 0x00, 0x7d, 0x8000, 0xffff, cart);
@@ -59,7 +59,7 @@ Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)psra
uint8 BSXCart::mmio_read(uint addr) {
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
uint8 n = (addr >> 16) & 15;
uint8 n = (addr >> 16) & 15;
return regs.r[n];
}
@@ -72,7 +72,7 @@ uint8 BSXCart::mmio_read(uint addr) {
void BSXCart::mmio_write(uint addr, uint8 data) {
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
uint8 n = (addr >> 16) & 15;
uint8 n = (addr >> 16) & 15;
regs.r[n] = data;
if(n == 0x0e && data & 0x80) update_memory_map();
return;
@@ -84,16 +84,16 @@ void BSXCart::mmio_write(uint addr, uint8 data) {
}
BSXCart::BSXCart() {
sram_data = (uint8*)malloc( 32 * 1024);
psram_data = (uint8*)malloc(512 * 1024);
sram_data = new uint8_t[ 32 * 1024];
psram_data = new uint8_t[512 * 1024];
sram.map (sram_data, 32 * 1024);
psram.map(psram_data, 512 * 1024);
}
BSXCart::~BSXCart() {
safe_free(sram_data);
safe_free(psram_data);
delete[] sram_data;
delete[] psram_data;
}
#endif //ifdef BSX_CPP

View File

@@ -1,6 +1,7 @@
#include "bsx/bsx.h"
#include "srtc/srtc.h"
#include "sdd1/sdd1.h"
#include "spc7110/spc7110.h"
#include "cx4/cx4.h"
#include "dsp1/dsp1.h"
#include "dsp2/dsp2.h"

697
src/chip/spc7110/codec.cpp Normal file
View File

@@ -0,0 +1,697 @@
const uint8_t SPC7110Codec::EvolutionTable[53][4] = {
//prob, nextlps, nextmps, toggle invert
{0x5a, 1, 1,1}, //0 l,m
{0x25, 6, 2,0}, //1 l,m
{0x11, 8, 3,0}, //2 l,m
{0x08, 10, 4,0}, //3 ,m
{0x03, 12, 5,0}, //4 ,m
{0x01, 15, 5,0}, //5 ,m
{0x5a, 7, 7,1}, //6 l,
{0x3f, 19, 8,0}, //7 l,m
{0x2c, 21, 9,0}, //8 l,m
{0x20, 22, 10,0}, //9 ,m
{0x17, 23, 11,0}, //10 ,m
{0x11, 25, 12,0}, //11 ,m
{0x0c, 26, 13,0}, //12 ,m
{0x09, 28, 14,0}, //13 ,m
{0x07, 29, 15,0}, //14 ,m
{0x05, 31, 16,0}, //15 ,m
{0x04, 32, 17,0}, //16 ,m
{0x03, 34, 18,0}, //17 ,m
{0x02, 35, 5,0}, //18 ,m
{0x5a, 20, 20,1}, //19 l,m
{0x48, 39, 21,0}, //20 l,m
{0x3a, 40, 22,0}, //21 l,m
{0x2e, 42, 23,0}, //22 l,m
{0x26, 44, 24,0}, //23 l,m
{0x1f, 45, 25,0}, //24 l,m
{0x19, 46, 26,0}, //25 l,m
{0x15, 25, 27,0}, //26 l,m
{0x11, 26, 28,0}, //27 l,m
{0x0e, 26, 29,0}, //28 l,m
{0x0b, 27, 30,0}, //29 ,m
{0x09, 28, 31,0}, //30 ,m
{0x08, 29, 32,0}, //31 l,m
{0x07, 30, 33,0}, //32 l,m
{0x05, 31, 34,0}, //33 l,m <--- changed lps
{0x04, 33, 35,0}, //34 ,m ... this is NOT skipped
{0x04, 33, 36,0}, //35 ,m
{0x03, 34, 37,0}, //36 ,m
{0x02, 35, 38,0}, //37 ,m ... this is NOT skipped
{0x02, 36, 5,0}, //38 ,m
{0x58, 39, 40,1}, //39 l,m
{0x4d, 47, 41,0}, //40 l,m
{0x43, 48, 42,0}, //41 ,m
{0x3b, 49, 43,0}, //42 ,m
{0x34, 50, 44,0}, //43 l,m
{0x2e, 51, 45,0}, //44 l,m
{0x29, 44, 46,0}, //45 l,m
{0x25, 45, 24,0}, //46 ,m
{0x56, 47, 48,1}, //47 l,m
{0x4f, 47, 49,0}, //48 l,m
{0x47, 48, 50,0}, //49 l,m
{0x41, 49, 51,0}, //50 l,m
{0x3c, 50, 52,0}, //51 l,m
{0x37, 51, 43,0} //52 ,m
};
const uint8_t SPC7110Codec::Mode2ContextTable[32][4] = {
// "bit" = (lps^invert)
//next_0, use ref pixel, next_1, use ref pixel
// if use ref pixel, then add on the 0-4 bell number grouping
{1, 0, 2, 0}, //0
{3, 1, 8, 1}, //1 prev bit 0
{13,0, 14,0}, //2 prev bit 1
{15,0, 16,0}, //3 prev bit 00
{17,0, 18,0}, //4
{19,0, 20,0}, //5
{21,0, 22,0}, //6
{23,0, 24,0}, //7
{25,0, 26,0}, //8 prev bit 01
{25,0, 26,0}, //9
{25,0, 26,0}, //10
{25,0, 26,0}, //11
{25,0, 26,0}, //12
{27,0, 28,0}, //13 prev bit 10
{29,0, 30,0}, //14 prev bit 11
{31,0, 31,0}, //15 000 ref group 0
{31,0, 31,0}, //16 001 ref group 0
{31,0, 31,0}, //17 000 ref group 1
{31,0, 31,0}, //18 001 ref group 1
{31,0, 31,0}, //19 000 ref group 2
{31,0, 31,0}, //20 001 ref group 2
{31,0, 31,0}, //21 000 ref group 3
{31,0, 31,0}, //22 001 ref group 3
{31,0, 31,0}, //23 000 ref group 4
{31,0, 31,0}, //24 001 ref group 4
{31,0, 31,0}, //25 010
{31,0, 31,0}, //26 011
{31,0, 31,0}, //27 100
{31,0, 31,0}, //28 101
{31,0, 31,0}, //29 110
{31,0, 31,0}, //30 111
{31,0, 31,0} //31 -- used as a trap for testing purposes --
};
#define PROB(x) EvolutionTable[Contexts[x].index][0]
#define NEXT_LPS(x) EvolutionTable[Contexts[x].index][1]
#define NEXT_MPS(x) EvolutionTable[Contexts[x].index][2]
#define TOGGLE_INVERT(x) EvolutionTable[Contexts[x].index][3]
#define BIT(x,y) ((x>>y)&1)
void SPC7110Codec::decomp_mode0(int len) {
uint8_t *datain = buffer;
uint8_t *dataout = output;
static const unsigned NUM_CONTEXTS = 30;
uint8 top,val;
uint8 con,mps,prob;
uint8 flag_lps,shift,mask;
int out=0;
int inverts=0;
int lps=0;
unsigned char in;
int in_count;
int i,bit;
//setup
top=0xFF;
val=*datain;
datain++;
in=*datain;
datain++;
in_count=8;
//reset context states
for(i=0;i<NUM_CONTEXTS;i++)
{
Contexts[i].index=0;
Contexts[i].invert=0;
}
for(i=0;i<len;i++)
{
if(i==-1800)
{
int k;
printf("\nEvolution table:\n");
//for(k=0;k<53;k++)
//printf(" %d,%d //%d\n",SeenEvolution[k][0],SeenEvolution[k][1],k);
}
for(bit=0;bit<8;bit++)
{
//get context
mask = (1<<(bit&3)) - 1;
con = mask + ((inverts&mask)^(lps&mask));
if(bit>3)
con+=15;
//get PROB and MPS
prob = PROB(con);
mps = (BIT(out,15) ^ Contexts[con].invert);
if(i>=15 && i<=18 && 0)
printf("byte %d bit %d: val=%.2X top=%.2X prob=%.2X mps=%d con=%d state=%d\n",
i,bit,val,top,prob,mps,con,Contexts[con].index);
//get bit
if (val <= top-prob)
{
//mps
top = top - prob;
out = (out << 1) + mps;
flag_lps=0;
}
else
{
//lps
val = val - (top - (prob - 1));
top = prob - 1;
out = (out << 1) + 1-mps;
flag_lps=1;
}
// renormalize
shift=0;
while(top<0x7F) // NOTE: not 0x80, it's a strange border case
{
shift++;
top = (top<<1)+1;
val = (val<<1)+(in>>7);
in = (in<<1);
if(--in_count==0)
{
in=*datain;
datain++;
in_count=8;
}
}
//update processing info
lps = (lps<<1) + flag_lps;
inverts = (inverts<<1) + Contexts[con].invert;
//update context state
if(flag_lps & TOGGLE_INVERT(con))
Contexts[con].invert ^= 1;
if(flag_lps)
{
//SeenEvolution[Contexts[con].index][0]=1;
Contexts[con].index = NEXT_LPS(con);
}
else if(shift)
{
//SeenEvolution[Contexts[con].index][1]=1;
Contexts[con].index = NEXT_MPS(con);
}
}
//save byte
*dataout = (out & 0xFF);
dataout++;
}
}
void SPC7110Codec::decomp_mode1(int len) {
uint8_t *datain = buffer;
uint8_t *dataout = output;
static const unsigned NUM_CONTEXTS = 15;
int pixelorder[4]={0,1,2,3};
int realorder[4];
int a,b,c;
int m,n;
uint8 top,val;
uint8 con,prob;
uint8 flag_lps,shift;
int out=0;
int inverts=0;
int lps=0;
unsigned char in;
int in_count;
int in_len=0;
int i,j,pixel;
//setup
top=0xFF;
val=datain[in_len++];
in=datain[in_len++];
in_count=8;
//reset context states
for(i=0;i<NUM_CONTEXTS;i++)
{
Contexts[i].index=0;
Contexts[i].invert=0;
}
for(i=0;i<len;i+=2)
{
if(i!=0)
{
//turn pixel data into bitplanes
//and save as output
*dataout = (BIT(out,15)<<7) + (BIT(out,13)<<6) + (BIT(out,11)<<5) + (BIT(out,9)<<4)
+ (BIT(out,7)<<3) + (BIT(out,5)<<2) + (BIT(out,3)<<1) + BIT(out,1);
dataout++;
*dataout = (BIT(out,14)<<7) + (BIT(out,12)<<6) + (BIT(out,10)<<5) + (BIT(out,8)<<4)
+ (BIT(out,6)<<3) + (BIT(out,4)<<2) + (BIT(out,2)<<1) + BIT(out,0);
dataout++;
}
for(pixel=0;pixel<8;pixel++)
{
//get first symbol context
a = ((out >> (1*2)) & 0x3);
b = ((out >> (7*2)) & 0x3);
c = ((out >> (8*2)) & 0x3);
if(a==b && b==c)
con=0;
else if (a==b && b!=c)
con=1;
else if (a!=b && b==c)
con=2;
else if (a==c && b!=c)
con=3;
else
con=4;
//update pixel order
for(m=0;m<4;m++)
if(pixelorder[m]==a)
break;
for(n=m;n>0;n--)
{
j=pixelorder[n-1];
pixelorder[n-1]=pixelorder[n];
pixelorder[n]=j;
}
//get PROB
prob = PROB(con);
//get symbol
if (val <= top-prob)
{
//mps
top = top - prob;
flag_lps=0;
}
else
{
//lps
val = val - (top - (prob - 1));
top = prob - 1;
flag_lps=1;
}
// renormalize
shift=0;
while(top<0x7F)
{
shift++;
top = (top<<1)+1;
val = (val<<1)+(in>>7);
in = (in<<1);
if(--in_count==0)
{
in=datain[in_len++];
in_count=8;
}
}
//update processing info
lps = (lps<<1) + flag_lps;
inverts = (inverts<<1) + Contexts[con].invert;
//update context state
if(flag_lps & TOGGLE_INVERT(con))
Contexts[con].invert ^= 1;
if(flag_lps)
Contexts[con].index = NEXT_LPS(con);
else if(shift)
Contexts[con].index = NEXT_MPS(con);
//get context of second symbol
con = 5 + con*2 + ((lps^inverts)&1);
//get PROB
prob = PROB(con);
//get symbol
if (val <= top-prob)
{
//mps
top = top - prob;
flag_lps=0;
}
else
{
//lps
val = val - (top - (prob - 1));
top = prob - 1;
flag_lps=1;
}
// renormalize
shift=0;
while(top<0x7F)
{
shift++;
top = (top<<1)+1;
val = (val<<1)+(in>>7);
in = (in<<1);
if(--in_count==0)
{
in=datain[in_len++];
in_count=8;
}
}
//calculate the real pixel order
for(m=0;m<4;m++)
realorder[m]=pixelorder[m];
//shift refence pixel c value to top
for(m=0;m<4;m++)
if(realorder[m]==c)
break;
for(n=m;n>0;n--)
{
j=realorder[n-1];
realorder[n-1]=realorder[n];
realorder[n]=j;
}
//shift refence pixel b value to top
for(m=0;m<4;m++)
if(realorder[m]==b)
break;
for(n=m;n>0;n--)
{
j=realorder[n-1];
realorder[n-1]=realorder[n];
realorder[n]=j;
}
//shift refence pixel a value to top
for(m=0;m<4;m++)
if(realorder[m]==a)
break;
for(n=m;n>0;n--)
{
j=realorder[n-1];
realorder[n-1]=realorder[n];
realorder[n]=j;
}
//update processing info
lps = (lps<<1) + flag_lps;
inverts = (inverts<<1) + Contexts[con].invert;
//update context state
if(flag_lps & TOGGLE_INVERT(con))
Contexts[con].invert ^= 1;
if(flag_lps)
Contexts[con].index = NEXT_LPS(con);
else if(shift)
Contexts[con].index = NEXT_MPS(con);
//get pixel
b=realorder[(lps^inverts)&3];
out = (out<<2) + b;
}
}
//turn pixel data into bitplanes
//and save as output.. BUT don't save second byte unless asked to
*dataout = (BIT(out,15)<<7) + (BIT(out,13)<<6) + (BIT(out,11)<<5) + (BIT(out,9)<<4)
+ (BIT(out,7)<<3) + (BIT(out,5)<<2) + (BIT(out,3)<<1) + BIT(out,1);
dataout++;
if((len&1)==0)
{
*dataout = (BIT(out,14)<<7) + (BIT(out,12)<<6) + (BIT(out,10)<<5) + (BIT(out,8)<<4)
+ (BIT(out,6)<<3) + (BIT(out,4)<<2) + (BIT(out,2)<<1) + BIT(out,0);
dataout++;
}
if(in_count==8)
in_len--;
//printf("Used %d bytes of input.\n",in_len);
//return in_len;
}
void SPC7110Codec::decomp_mode2(int len) {
uint8_t *datain = buffer;
uint8_t *dataout = output;
static const unsigned NUM_CONTEXTS = 32;
int pixelorder[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int realorder[16];
int a,b,c;
int m,n;
uint8 bitplanebuffer[16];
uint8 buf_idx=0;
uint8 top,val,prob;
uint8 con,refcon;
uint8 flag_lps,invertbit,shift;
int out=0;
int out2=0;
int inverts=0;
int lps=0;
unsigned char in;
int in_count;
int in_len=0;
int i,j,pixel,bit;
//setup
top=0xFF;
val=datain[in_len++];
in=datain[in_len++];
in_count=8;
//reset context states
for(i=0;i<NUM_CONTEXTS;i++)
{
Contexts[i].index=0;
Contexts[i].invert=0;
}
for(i=0;i<len;i+=2)
{
for(pixel=0;pixel<8;pixel++)
{
//get first symbol context
a = ((out >> (0*4)) & 0x0F);
b = ((out >> (7*4)) & 0x0F);
c = ((out2>> (0*4)) & 0x0F);
if(a==b && b==c)
refcon=0;
else if (a==b && b!=c)
refcon=1;
else if (a!=b && b==c)
refcon=2;
else if (a==c && b!=c)
refcon=3;
else
refcon=4;
con=0;
//update pixel order
for(m=0;m<16;m++)
if(pixelorder[m]==a)
break;
for(n=m;n>0;n--)
{
j=pixelorder[n-1];
pixelorder[n-1]=pixelorder[n];
pixelorder[n]=j;
}
//calculate the real pixel order
for(m=0;m<16;m++)
realorder[m]=pixelorder[m];
//shift refence pixel c value to top
for(m=0;m<16;m++)
if(realorder[m]==c)
break;
for(n=m;n>0;n--)
{
j=realorder[n-1];
realorder[n-1]=realorder[n];
realorder[n]=j;
}
//shift refence pixel b value to top
for(m=0;m<16;m++)
if(realorder[m]==b)
break;
for(n=m;n>0;n--)
{
j=realorder[n-1];
realorder[n-1]=realorder[n];
realorder[n]=j;
}
//shift refence pixel a value to top
for(m=0;m<16;m++)
if(realorder[m]==a)
break;
for(n=m;n>0;n--)
{
j=realorder[n-1];
realorder[n-1]=realorder[n];
realorder[n]=j;
}
//get 4 symbols
for(bit=0;bit<4;bit++)
{
//get PROB
prob = PROB(con);
//get symbol
if (val <= top-prob)
{
//mps
top = top - prob;
flag_lps=0;
}
else
{
//lps
val = val - (top - (prob - 1));
top = prob - 1;
flag_lps=1;
}
// renormalize
shift=0;
while(top<0x7F)
{
shift++;
top = (top<<1)+1;
val = (val<<1)+(in>>7);
in = (in<<1);
if(--in_count==0)
{
in=datain[in_len++];
in_count=8;
}
}
//update processing info
lps = (lps<<1) + flag_lps;
invertbit = Contexts[con].invert;
inverts = (inverts<<1) + Contexts[con].invert;
//update context state
if(flag_lps & TOGGLE_INVERT(con))
Contexts[con].invert ^= 1;
if(flag_lps)
Contexts[con].index = NEXT_LPS(con);
else if(shift)
Contexts[con].index = NEXT_MPS(con);
//get next context
if(Mode2ContextTable[con][2*(flag_lps^invertbit)+1])
con=Mode2ContextTable[con][2*(flag_lps^invertbit)]+refcon;
else
con=Mode2ContextTable[con][2*(flag_lps^invertbit)];
}
//get pixel
b=realorder[(lps^inverts)&0x0F];
out2 = (out2<<4) + ((out>>28)&0x0F);
out = (out<<4) + b;
}
//cludge to convert pixel data into bitplanes and respect len parameter for output buf
*dataout = (BIT(out,31)<<7) + (BIT(out,27)<<6) + (BIT(out,23)<<5) + (BIT(out,19)<<4)
+ (BIT(out,15)<<3) + (BIT(out,11)<<2) + (BIT(out,7)<<1) + BIT(out,3);
dataout++;
if((i+1)<len)
{
*dataout = (BIT(out,30)<<7) + (BIT(out,26)<<6) + (BIT(out,22)<<5) + (BIT(out,18)<<4)
+ (BIT(out,14)<<3) + (BIT(out,10)<<2) + (BIT(out,6)<<1) + BIT(out,2);
dataout++;
}
bitplanebuffer[buf_idx++] =
(BIT(out,29)<<7) + (BIT(out,25)<<6) + (BIT(out,21)<<5) + (BIT(out,17)<<4)
+ (BIT(out,13)<<3) + (BIT(out,9)<<2) + (BIT(out,5)<<1) + BIT(out,1);
bitplanebuffer[buf_idx++] =
(BIT(out,28)<<7) + (BIT(out,24)<<6) + (BIT(out,20)<<5) + (BIT(out,16)<<4)
+ (BIT(out,12)<<3) + (BIT(out,8)<<2) + (BIT(out,4)<<1) + BIT(out,0);
if(buf_idx==16)
{
for(m=0;m<16 && i+2<len;m++,i++)
{
*dataout = bitplanebuffer[m];
dataout++;
}
buf_idx=0;
}
}
if(in_count==8)
in_len--;
//printf("Used %d bytes of input.\n",in_len);
//return in_len;
}
#undef PROB
#undef NEXT_LPS
#undef NEXT_MPS
#undef TOGGLE_INVERT
#undef BIT
SPC7110Codec::SPC7110Codec() {
buffer = new(zeromemory) uint8_t[65536];
output = new(zeromemory) uint8_t[65536];
}
SPC7110Codec::~SPC7110Codec() {
delete[] buffer;
delete[] output;
}

20
src/chip/spc7110/codec.h Normal file
View File

@@ -0,0 +1,20 @@
class SPC7110Codec {
public:
uint8_t *buffer;
uint8_t *output;
void decomp_mode0(int len);
void decomp_mode1(int len);
void decomp_mode2(int len);
SPC7110Codec();
~SPC7110Codec();
private:
static const uint8_t EvolutionTable[53][4];
static const uint8_t Mode2ContextTable[32][4];
struct ContextState {
uint8_t index;
uint8_t invert;
} Contexts[32];
};

View File

@@ -0,0 +1,690 @@
#include "../../base.h"
#define SPC7110_CPP
#include "codec.cpp"
const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
void SPC7110::init() {}
void SPC7110::enable() {
uint16_t limit = (cartridge.info.spc7110rtc ? 0x4842 : 0x483f);
for(uint16_t i = 0x4800; i <= limit; i++) memory::mmio.map(i, *this);
}
void SPC7110::power() {
reset();
}
void SPC7110::reset() {
r4801 = 0x00;
r4802 = 0x00;
r4803 = 0x00;
r4804 = 0x00;
r4805 = 0x00;
r4806 = 0x00;
r4807 = 0x00;
r4808 = 0x00;
r4809 = 0x00;
r480a = 0x00;
r480b = 0x00;
r480c = 0x00;
memset(codec.output, 0, 65536);
memset(codec.buffer, 0, 65536);
decomp_offset = 0;
r4811 = 0x00;
r4812 = 0x00;
r4813 = 0x00;
r4814 = 0x00;
r4815 = 0x00;
r4816 = 0x00;
r4817 = 0x00;
r4818 = 0x00;
r481x = 0x00;
r4814_latch = false;
r4815_latch = false;
r4820 = 0x00;
r4821 = 0x00;
r4822 = 0x00;
r4823 = 0x00;
r4824 = 0x00;
r4825 = 0x00;
r4826 = 0x00;
r4827 = 0x00;
r4828 = 0x00;
r4829 = 0x00;
r482a = 0x00;
r482b = 0x00;
r482c = 0x00;
r482d = 0x00;
r482e = 0x00;
r482f = 0x00;
r4830 = 0x00;
mmio_write(0x4831, 0);
mmio_write(0x4832, 1);
mmio_write(0x4833, 2);
r4834 = 0x00;
r4840 = 0x00;
r4841 = 0x00;
r4842 = 0x00;
if(cartridge.info.spc7110rtc) {
rtc_state = RTCS_Inactive;
rtc_mode = RTCM_Linear;
rtc_index = 0;
}
}
unsigned SPC7110::datarom_addr(unsigned addr) {
unsigned size = memory::cartrom.size() - 0x100000;
while(addr >= size) addr -= size;
return addr + 0x100000;
}
unsigned SPC7110::data_pointer() { return r4811 + (r4812 << 8) + (r4813 << 16); }
unsigned SPC7110::data_adjust() { return r4814 + (r4815 << 8); }
unsigned SPC7110::data_increment() { return r4816 + (r4817 << 8); }
void SPC7110::set_data_pointer(unsigned addr) { r4811 = addr; r4812 = addr >> 8; r4813 = addr >> 16; }
void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; }
void SPC7110::update_time(int offset) {
time_t rtc_time;
rtc_time = memory::cartrtc.read(16);
rtc_time |= memory::cartrtc.read(17) << 8;
rtc_time |= memory::cartrtc.read(18) << 16;
rtc_time |= memory::cartrtc.read(19) << 24;
bool update = true;
if(memory::cartrtc.read(13) & 1) update = false; //do not update if CR0 timer disable flag is set
if(memory::cartrtc.read(15) & 3) update = false; //do not update if CR2 timer disable flags are set
time_t current_time = time(0) - offset;
if(update && current_time > rtc_time) {
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
unsigned month = memory::cartrtc.read( 8) + memory::cartrtc.read( 9) * 10;
unsigned year = memory::cartrtc.read(10) + memory::cartrtc.read(11) * 10;
unsigned weekday = memory::cartrtc.read(12);
day--;
month--;
year += (year >= 90) ? 1900 : 2000; //range = 1990-2089
second += (unsigned)(current_time - rtc_time);
while(second >= 60) {
second -= 60;
minute++;
if(minute < 60) continue;
minute = 0;
hour++;
if(hour < 24) continue;
hour = 0;
day++;
weekday = (weekday + 1) % 7;
unsigned days = months[month % 12];
if(days == 28) {
bool leapyear = false;
if((year % 4) == 0) {
leapyear = true;
if((year % 100) == 0 && (year % 400) != 0) leapyear = false;
}
if(leapyear) days++;
}
if(day < days) continue;
day = 0;
month++;
if(month < 12) continue;
month = 0;
year++;
}
day++;
month++;
year %= 100;
memory::cartrtc.write( 0, second % 10);
memory::cartrtc.write( 1, second / 10);
memory::cartrtc.write( 2, minute % 10);
memory::cartrtc.write( 3, minute / 10);
memory::cartrtc.write( 4, hour % 10);
memory::cartrtc.write( 5, hour / 10);
memory::cartrtc.write( 6, day % 10);
memory::cartrtc.write( 7, day / 10);
memory::cartrtc.write( 8, month % 10);
memory::cartrtc.write( 9, month / 10);
memory::cartrtc.write(10, year % 10);
memory::cartrtc.write(11, (year / 10) % 10);
memory::cartrtc.write(12, weekday % 7);
}
memory::cartrtc.write(16, current_time);
memory::cartrtc.write(17, current_time >> 8);
memory::cartrtc.write(18, current_time >> 16);
memory::cartrtc.write(19, current_time >> 24);
}
uint8 SPC7110::mmio_read(uint addr) {
addr &= 0xffff;
switch(addr) {
//==================
//decompression unit
//==================
case 0x4800: {
uint16 counter = (r4809 + (r480a << 8));
counter--;
r4809 = counter;
r480a = counter >> 8;
return codec.output[(decomp_offset++) & 0xffff];
}
case 0x4801: return r4801;
case 0x4802: return r4802;
case 0x4803: return r4803;
case 0x4804: return r4804;
case 0x4805: return r4805;
case 0x4806: return r4806;
case 0x4807: return r4807;
case 0x4808: return r4808;
case 0x4809: return r4809;
case 0x480a: return r480a;
case 0x480b: return r480b;
case 0x480c: {
uint8 status = r480c;
r480c &= 0x7f;
return status;
}
//==============
//data port unit
//==============
case 0x4810: {
if(r481x != 0x1f) return 0x00;
unsigned addr = data_pointer();
unsigned adjust = data_adjust();
if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend
unsigned adjustaddr = addr;
if(r4818 & 2) {
adjustaddr += adjust;
set_data_adjust(adjust + 1);
}
uint8 data = memory::cartrom.read(datarom_addr(adjustaddr));
if(!(r4818 & 2)) {
unsigned increment = (r4818 & 1) ? data_increment() : 1;
if(r4818 & 4) increment = (int16)increment; //16-bit sign extend
if((r4818 & 16) == 0) {
set_data_pointer(addr + increment);
} else {
set_data_adjust(adjust + increment);
}
}
return data;
}
case 0x4811: return r4811;
case 0x4812: return r4812;
case 0x4813: return r4813;
case 0x4814: return r4814;
case 0x4815: return r4815;
case 0x4816: return r4816;
case 0x4817: return r4817;
case 0x4818: return r4818;
case 0x481a: {
if(r481x != 0x1f) return 0x00;
unsigned addr = data_pointer();
unsigned adjust = data_adjust();
if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend
uint8 data = memory::cartrom.read(datarom_addr(addr + adjust));
if((r4818 & 0x60) == 0x60) {
if((r4818 & 16) == 0) {
set_data_pointer(addr + adjust);
} else {
set_data_adjust(adjust + adjust);
}
}
return data;
}
//=========
//math unit
//=========
case 0x4820: return r4820;
case 0x4821: return r4821;
case 0x4822: return r4822;
case 0x4823: return r4823;
case 0x4824: return r4824;
case 0x4825: return r4825;
case 0x4826: return r4826;
case 0x4827: return r4827;
case 0x4828: return r4828;
case 0x4829: return r4829;
case 0x482a: return r482a;
case 0x482b: return r482b;
case 0x482c: return r482c;
case 0x482d: return r482d;
case 0x482e: return r482e;
case 0x482f: {
uint8 status = r482f;
r482f &= 0x7f;
return status;
}
//===================
//memory mapping unit
//===================
case 0x4830: return r4830;
case 0x4831: return r4831;
case 0x4832: return r4832;
case 0x4833: return r4833;
case 0x4834: return r4834;
//====================
//real-time clock unit
//====================
case 0x4840: return r4840;
case 0x4841: {
if(rtc_state == RTCS_Inactive || rtc_state == RTCS_ModeSelect) return 0x00;
r4842 = 0x80;
uint8 data = memory::cartrtc.read(rtc_index);
rtc_index = (rtc_index + 1) & 15;
return data;
}
case 0x4842: {
uint8 status = r4842;
r4842 &= 0x7f;
return status;
}
}
return cpu.regs.mdr;
}
void SPC7110::mmio_write(uint addr, uint8 data) {
addr &= 0xffff;
switch(addr) {
//==================
//decompression unit
//==================
case 0x4801: r4801 = data; break;
case 0x4802: r4802 = data; break;
case 0x4803: r4803 = data; break;
case 0x4804: r4804 = data; break;
case 0x4805: r4805 = data; break;
case 0x4806: {
r4806 = data;
unsigned table = (r4801 + (r4802 << 8) + (r4803 << 16));
unsigned index = (r4804 << 2);
unsigned length = (r4809 + (r480a << 8));
unsigned addr = datarom_addr(table + index);
unsigned mode = (memory::cartrom.read(addr + 0));
unsigned offset = (memory::cartrom.read(addr + 1) << 16)
+ (memory::cartrom.read(addr + 2) << 8)
+ (memory::cartrom.read(addr + 3) << 0);
//this can technically be 65536, but it has never been observed higher than 32768 ...
//really need a way to determine both compressed and decompressed lengths, though.
static const unsigned max_length = 32768;
offset = datarom_addr(offset);
for(unsigned i = 0; i < max_length; i++) codec.buffer[i] = memory::cartrom.read(offset + i);
#if 0
printf("decompression: 4805=$%0.2x,4806=$%0.2x,4807=$%0.2x,4808=$%0.2x,480b=$%0.2x\n",
r4805, r4806, r4807, r4808, r480b);
printf("table=$%0.6x,index=%3d,length=%5d,mode=%d,offset=$%0.6x\n",
table, r4804, length, mode, offset);
#endif
switch(mode) {
case 0: codec.decomp_mode0(max_length); break;
case 1: codec.decomp_mode1(max_length); break;
case 2: codec.decomp_mode2(max_length); break;
}
decomp_offset = (r4805 + (r4806 << 8)) << mode;
r480c = 0x80;
} break;
case 0x4807: r4807 = data; break;
case 0x4808: r4808 = data; break;
case 0x4809: r4809 = data; break;
case 0x480a: r480a = data; break;
case 0x480b: r480b = data; break;
//==============
//data port unit
//==============
case 0x4811: r4811 = data; r481x |= 0x01; break;
case 0x4812: r4812 = data; r481x |= 0x02; break;
case 0x4813: r4813 = data; r481x |= 0x04; break;
case 0x4814: {
r4814 = data;
r481x |= 0x08;
r4814_latch = true;
if(!r4815_latch) break;
if(!(r4818 & 2)) break;
if(r4818 & 0x10) break;
if((r4818 & 0x60) == 0x20) {
unsigned increment = data_adjust() & 0xff;
if(r4818 & 8) increment = (int8)increment; //8-bit sign extend
set_data_pointer(data_pointer() + increment);
} else if((r4818 & 0x60) == 0x40) {
unsigned increment = data_adjust();
if(r4818 & 8) increment = (int16)increment; //16-bit sign extend
set_data_pointer(data_pointer() + increment);
}
} break;
case 0x4815: {
r4815 = data;
r481x |= 0x10;
r4815_latch = true;
if(!r4814_latch) break;
if(!(r4818 & 2)) break;
if(r4818 & 0x10) break;
if((r4818 & 0x60) == 0x20) {
unsigned increment = data_adjust() & 0xff;
if(r4818 & 8) increment = (int8)increment; //8-bit sign extend
set_data_pointer(data_pointer() + increment);
} else if((r4818 & 0x60) == 0x40) {
unsigned increment = data_adjust();
if(r4818 & 8) increment = (int16)increment; //16-bit sign extend
set_data_pointer(data_pointer() + increment);
}
} break;
case 0x4816: r4816 = data; break;
case 0x4817: r4817 = data; break;
case 0x4818: {
if(r481x != 0x1f) break;
r4818 = data;
r4814_latch = r4815_latch = false;
} break;
//=========
//math unit
//=========
case 0x4820: r4820 = data; break;
case 0x4821: r4821 = data; break;
case 0x4822: r4822 = data; break;
case 0x4823: r4823 = data; break;
case 0x4824: r4824 = data; break;
case 0x4825: {
r4825 = data;
if(r482e & 1) {
//signed 16-bit x 16-bit multiplication
int16 r0 = (int16)(r4824 + (r4825 << 8));
int16 r1 = (int16)(r4820 + (r4821 << 8));
signed result = r0 * r1;
r4828 = result;
r4829 = result >> 8;
r482a = result >> 16;
r482b = result >> 24;
} else {
//unsigned 16-bit x 16-bit multiplication
uint16 r0 = (uint16)(r4824 + (r4825 << 8));
uint16 r1 = (uint16)(r4820 + (r4821 << 8));
unsigned result = r0 * r1;
r4828 = result;
r4829 = result >> 8;
r482a = result >> 16;
r482b = result >> 24;
}
r482f = 0x80;
} break;
case 0x4826: r4826 = data; break;
case 0x4827: {
r4827 = data;
if(r482e & 1) {
//signed 32-bit x 16-bit division
int32 dividend = (int32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24));
int16 divisor = (int16)(r4826 + (r4827 << 8));
int32 quotient;
int16 remainder;
if(divisor) {
quotient = (int32)(dividend / divisor);
remainder = (int32)(dividend % divisor);
} else {
//illegal division by zero
quotient = 0;
remainder = dividend & 0xffff;
}
r4828 = quotient;
r4829 = quotient >> 8;
r482a = quotient >> 16;
r482b = quotient >> 24;
r482c = remainder;
r482d = remainder >> 8;
} else {
//unsigned 32-bit x 16-bit division
uint32 dividend = (uint32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24));
uint16 divisor = (uint16)(r4826 + (r4827 << 8));
uint32 quotient;
uint16 remainder;
if(divisor) {
quotient = (uint32)(dividend / divisor);
remainder = (uint16)(dividend % divisor);
} else {
//illegal division by zero
quotient = 0;
remainder = dividend & 0xffff;
}
r4828 = quotient;
r4829 = quotient >> 8;
r482a = quotient >> 16;
r482b = quotient >> 24;
r482c = remainder;
r482d = remainder >> 8;
}
r482f = 0x80;
} break;
case 0x482e: {
//reset math unit
r4820 = r4821 = r4822 = r4823 = 0;
r4824 = r4825 = r4826 = r4827 = 0;
r4828 = r4829 = r482a = r482b = 0;
r482c = r482d = 0;
r482e = data;
} break;
//===================
//memory mapping unit
//===================
case 0x4830: r4830 = data; break;
case 0x4831: {
r4831 = data;
dx_offset = datarom_addr((data & 7) * 0x100000);
} break;
case 0x4832: {
r4832 = data;
ex_offset = datarom_addr((data & 7) * 0x100000);
} break;
case 0x4833: {
r4833 = data;
fx_offset = datarom_addr((data & 7) * 0x100000);
} break;
case 0x4834: r4834 = data; break;
//====================
//real-time clock unit
//====================
case 0x4840: {
r4840 = data;
if(!(r4840 & 1)) {
//disable RTC
rtc_state = RTCS_Inactive;
update_time();
} else {
//enable RTC
r4842 = 0x80;
rtc_state = RTCS_ModeSelect;
}
} break;
case 0x4841: {
r4841 = data;
switch(rtc_state) {
case RTCS_ModeSelect: {
if(data == RTCM_Linear || data == RTCM_Indexed) {
r4842 = 0x80;
rtc_state = RTCS_IndexSelect;
rtc_mode = (RTC_Mode)data;
rtc_index = 0;
}
} break;
case RTCS_IndexSelect: {
r4842 = 0x80;
rtc_index = data & 15;
if(rtc_mode == RTCM_Linear) rtc_state = RTCS_Write;
} break;
case RTCS_Write: {
r4842 = 0x80;
//control register 0
if(rtc_index == 13) {
//increment second counter
if(data & 2) update_time(+1);
//round minute counter
if(data & 8) {
update_time();
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
//clear seconds
memory::cartrtc.write(0, 0);
memory::cartrtc.write(1, 0);
if(second >= 30) update_time(+60);
}
}
//control register 2
if(rtc_index == 15) {
//disable timer and clear second counter
if((data & 1) && !(memory::cartrtc.read(15) & 1)) {
update_time();
//clear seconds
memory::cartrtc.write(0, 0);
memory::cartrtc.write(1, 0);
}
//disable timer
if((data & 2) && !(memory::cartrtc.read(15) & 2)) {
update_time();
}
}
memory::cartrtc.write(rtc_index, data & 15);
rtc_index = (rtc_index + 1) & 15;
} break;
} //switch(rtc_state)
} break;
}
}
uint8 SPC7110::read(uint addr) {
if((addr & 0xffe000) == 0x006000 || (addr & 0xffe000) == 0x306000) {
//$[00|30]:[6000-7fff]
return memory::cartram.read(addr & 0x1fff);
}
if((addr & 0x708000) == 0x008000) {
//$[00-0f|80-8f]:[8000-ffff]
return memory::cartrom.read(addr & 0x0fffff);
}
if((addr & 0xff0000) == 0x500000) {
//$[50]:[0000-ffff]
return mmio_read(0x4800);
}
if((addr & 0xf00000) == 0xc00000) {
//$[c0-cf]:[0000-ffff]
return memory::cartrom.read(addr & 0x0fffff);
}
if((addr & 0xf00000) == 0xd00000) {
//$[d0-df]:[0000-ffff]
return memory::cartrom.read(dx_offset + (addr & 0x0fffff));
}
if((addr & 0xf00000) == 0xe00000) {
//$[e0-ef]:[0000-ffff]
return memory::cartrom.read(ex_offset + (addr & 0x0fffff));
}
if((addr & 0xf00000) == 0xf00000) {
//$[f0-ff]:[0000-ffff]
return memory::cartrom.read(fx_offset + (addr & 0x0fffff));
}
return cpu.regs.mdr;
}
void SPC7110::write(uint addr, uint8 data) {
if((addr & 0xffe000) == 0x006000 || (addr & 0xffe000) == 0x306000) {
//$[00|30]:[6000-7fff]
if(r4830 & 0x80) memory::cartram.write(addr & 0x1fff, data);
return;
}
}
SPC7110::SPC7110() {
}

130
src/chip/spc7110/spc7110.h Normal file
View File

@@ -0,0 +1,130 @@
/*****
* SPC7110 emulator - version 0.1 (2008-07-19)
* Copyright (c) 2008, byuu and neviksti
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* The software is provided "as is" and the author disclaims all warranties
* with regard to this software including all implied warranties of
* merchantibility and fitness, in no event shall the author be liable for
* any special, direct, indirect, or consequential damages or any damages
* whatsoever resulting from loss of use, data or profits, whether in an
* action of contract, negligence or other tortious action, arising out of
* or in connection with the use or performance of this software.
*****/
#include "codec.h"
class SPC7110 : public MMIO, public Memory {
public:
void init();
void enable();
void power();
void reset();
unsigned datarom_addr(unsigned addr);
unsigned data_pointer();
unsigned data_adjust();
unsigned data_increment();
void set_data_pointer(unsigned addr);
void set_data_adjust(unsigned addr);
void update_time(int offset = 0);
time_t create_time();
uint8 mmio_read (uint addr);
void mmio_write(uint addr, uint8 data);
uint8 read (uint addr);
void write(uint addr, uint8 data);
SPC7110();
private:
//==================
//decompression unit
//==================
uint8 r4801; //compression table low
uint8 r4802; //compression table high
uint8 r4803; //compression table bank
uint8 r4804; //compression table index
uint8 r4805; //decompression buffer index low
uint8 r4806; //decompression buffer index high
uint8 r4807; //???
uint8 r4808; //???
uint8 r4809; //compression length low
uint8 r480a; //compression length high
uint8 r480b; //decompression control register
uint8 r480c; //decompression status
SPC7110Codec codec;
uint16 decomp_offset;
//==============
//data port unit
//==============
uint8 r4811; //data pointer low
uint8 r4812; //data pointer high
uint8 r4813; //data pointer bank
uint8 r4814; //data adjust low
uint8 r4815; //data adjust high
uint8 r4816; //data increment low
uint8 r4817; //data increment high
uint8 r4818; //data port control register
uint8 r481x;
bool r4814_latch;
bool r4815_latch;
//=========
//math unit
//=========
uint8 r4820; //16-bit multiplicand B0, 32-bit dividend B0
uint8 r4821; //16-bit multiplicand B1, 32-bit dividend B1
uint8 r4822; //32-bit dividend B2
uint8 r4823; //32-bit dividend B3
uint8 r4824; //16-bit multiplier B0
uint8 r4825; //16-bit multiplier B1
uint8 r4826; //16-bit divisor B0
uint8 r4827; //16-bit divisor B1
uint8 r4828; //32-bit product B0, 32-bit quotient B0
uint8 r4829; //32-bit product B1, 32-bit quotient B1
uint8 r482a; //32-bit product B2, 32-bit quotient B2
uint8 r482b; //32-bit product B3, 32-bit quotient B3
uint8 r482c; //16-bit remainder B0
uint8 r482d; //16-bit remainder B1
uint8 r482e; //math control register
uint8 r482f; //math status
//===================
//memory mapping unit
//===================
uint8 r4830; //SRAM write enable
uint8 r4831; //$[d0-df]:[0000-ffff] mapping
uint8 r4832; //$[e0-ef]:[0000-ffff] mapping
uint8 r4833; //$[f0-ff]:[0000-ffff] mapping
uint8 r4834; //???
unsigned dx_offset;
unsigned ex_offset;
unsigned fx_offset;
//====================
//real-time clock unit
//====================
uint8 r4840; //RTC latch
uint8 r4841; //RTC index/data port
uint8 r4842; //RTC status
enum RTC_State { RTCS_Inactive, RTCS_ModeSelect, RTCS_IndexSelect, RTCS_Write } rtc_state;
enum RTC_Mode { RTCM_Linear = 0x03, RTCM_Indexed = 0x0c } rtc_mode;
unsigned rtc_index;
static const unsigned months[12];
};
extern SPC7110 spc7110;

View File

@@ -1,189 +1,213 @@
/*
S-RTC chip emulation
Used by Hudson Soft in Dai Kaijuu Monogatari II and Far East of Eden Zero.
Currently, only the former is supported by bsnes.
Original S-RTC emulation code via John Weidman/SNES9x
Rewritten for compatibility with bsnes via byuu
The S-RTC is a real-time clock chip that was added to the above two carts
to allow the games to maintain the current time, even when the game was not
powered on. Thus allowing special events at certain times, and on certain
dates. Hudson Soft called this the PLG (Player's Life Gameplay System).
This chip is a special case to the term 'emulation' itself.
There are a few different ways to go about emulating this chip, and each
result in a different style of emulation.
The first is to simply return the current PC system time when the S-RTC is
read from. This emulates the original S-RTC in the sense that it always
returns the true current time, ignoring the speed that the SNES itself is
running at. The downside to this method is that you lose the ability to set
the time to whatever you choose inside the game itself. It will always return
the true time, regardless. This can be overcome by changing the PC system time,
which actually adds a greater degree of control over event timing, very useful
for emulation. It also has a timeshifting flaw discussed below.
The second is to run the S-RTC relative to the SNES speed. This means that
if the emulator is sped up (via fast forward key, frameskipping, etc), or
slowed down (via slowdown key, system bottlenecking, etc); the time increments
slower, thus ~60 frames on the SNES equal one second. Without this, timeshifting
will occur between the S-RTC and the real SNES.
The third and final method is to save a copy of the local system time when the
S-RTC is initially set, and compare the current system time against this value
when setting the S-RTC time. This overcomes the first methods' shortcoming of
not allowing the player to set the time in-game, however a new problem arises.
You now have to save the time when the RTC was initially set to both savestates
and to save-game data. This would require an extra file, or the breaking of
perhaps the only standard format (.srm savegame backups) in the entire SNES
emulation scene. You also give up the control of being able to override the
RTC clock at will via the PC system time outside of emulation.
The first method has another advantage over the third: Dai Kaijuu Monogatari II
only allows dates in the range of the years 1996-2199. The first method gets
around this limitation. But who knows, maybe it will break something in the
game if the date exceeds 2199... I guess we'll worry about that in two hundred
years from now.
For my implementation, I chose to go with the first method. Both for simplicity
and because I did not wish to create a new method for saving the system time
whenever the RTC is set.
*/
#include "../../base.h"
void SRTC::set_time() {
time_t rawtime;
tm *t;
::time(&rawtime);
t = localtime(&rawtime);
//see srtc.h for format of srtc.data[]
srtc.data[0] = t->tm_sec % 10;
srtc.data[1] = t->tm_sec / 10;
srtc.data[2] = t->tm_min % 10;
srtc.data[3] = t->tm_min / 10;
srtc.data[4] = t->tm_hour % 10;
srtc.data[5] = t->tm_hour / 10;
srtc.data[6] = t->tm_mday % 10;
srtc.data[7] = t->tm_mday / 10;
srtc.data[8] = t->tm_mon + 1;
srtc.data[9] = t->tm_year % 10;
srtc.data[10] = (t->tm_year / 10) % 10;
srtc.data[11] = 9 + (t->tm_year / 100);
srtc.data[12] = t->tm_wday;
}
void SRTC::init() {}
void SRTC::enable() {
memory::mmio.map(0x2800, *this);
memory::mmio.map(0x2801, *this);
}
void SRTC::power() {
memset(&srtc, 0, sizeof(srtc));
reset();
}
void SRTC::reset() {
srtc.index = -1;
srtc.mode = SRTC_READ;
}
uint8 SRTC::mmio_read(uint addr) {
switch(addr & 0xffff) {
case 0x2800: {
if(srtc.mode == SRTC_READ) {
if(srtc.index < 0) {
set_time();
srtc.index++;
return 0x0f; //send start message
} else if(srtc.index > MAX_SRTC_INDEX) {
srtc.index = -1;
return 0x0f; //send finished message
} else {
return srtc.data[srtc.index++];
}
} else {
return 0x00;
}
} break;
case 0x2801: {
} break;
}
return cpu.regs.mdr;
}
//Please see notes above about the implementation of the S-RTC
//Writes are stored the srtc.data[] array, but they are ignored
//as reads will refresh the data array with the current system
//time. The write method is only here for the sake of faux
//emulation of the real hardware.
void SRTC::mmio_write(uint addr, uint8 data) {
switch(addr & 0xffff) {
case 0x2800: {
} break;
case 0x2801: {
data &= 0x0f; //only the low four bits are used
if(data >= 0x0d) {
switch(data) {
case 0x0d:
srtc.mode = SRTC_READ;
srtc.index = -1;
break;
case 0x0e:
srtc.mode = SRTC_COMMAND;
break;
case 0x0f:
//unknown behaviour
break;
}
return;
}
if(srtc.mode == SRTC_WRITE) {
if(srtc.index >= 0 && srtc.index < MAX_SRTC_INDEX) {
srtc.data[srtc.index++] = data;
if(srtc.index == MAX_SRTC_INDEX) {
//all S-RTC data has been loaded by program
srtc.data[srtc.index++] = 0x00; //day_of_week
}
}
} else if(srtc.mode == SRTC_COMMAND) {
switch(data) {
case SRTC_COMMAND_CLEAR:
memset(srtc.data, 0, MAX_SRTC_INDEX + 1);
srtc.index = -1;
srtc.mode = SRTC_READY;
break;
case SRTC_COMMAND_WRITE:
srtc.index = 0;
srtc.mode = SRTC_WRITE;
break;
default:
//unknown behaviour
srtc.mode = SRTC_READY;
break;
}
} else {
if(srtc.mode == SRTC_READ) {
//ignore writes while in read mode
} else if(srtc.mode == SRTC_READY) {
//unknown behaviour
}
}
} break;
}
}
SRTC::SRTC() {}
#include "../../base.h"
const unsigned SRTC::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
void SRTC::init() {
}
void SRTC::enable() {
memory::mmio.map(0x2800, *this);
memory::mmio.map(0x2801, *this);
}
void SRTC::power() {
reset();
}
void SRTC::reset() {
rtc_mode = RTCM_Read;
rtc_index = -1;
update_time();
}
void SRTC::update_time() {
time_t rtc_time;
rtc_time = memory::cartrtc.read(16);
rtc_time |= memory::cartrtc.read(17) << 8;
rtc_time |= memory::cartrtc.read(18) << 16;
rtc_time |= memory::cartrtc.read(19) << 24;
time_t current_time = time(0);
if(current_time > rtc_time) {
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
unsigned month = memory::cartrtc.read( 8);
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
unsigned weekday = memory::cartrtc.read(12);
day--;
month--;
year += 1000;
second += (unsigned)(current_time - rtc_time);
while(second >= 60) {
second -= 60;
minute++;
if(minute < 60) continue;
minute = 0;
hour++;
if(hour < 24) continue;
hour = 0;
day++;
weekday = (weekday + 1) % 7;
unsigned days = months[month % 12];
if(days == 28) {
bool leapyear = false;
if((year % 4) == 0) {
leapyear = true;
if((year % 100) == 0 && (year % 400) != 0) leapyear = false;
}
if(leapyear) days++;
}
if(day < days) continue;
day = 0;
month++;
if(month < 12) continue;
month = 0;
year++;
}
day++;
month++;
year -= 1000;
memory::cartrtc.write( 0, second % 10);
memory::cartrtc.write( 1, second / 10);
memory::cartrtc.write( 2, minute % 10);
memory::cartrtc.write( 3, minute / 10);
memory::cartrtc.write( 4, hour % 10);
memory::cartrtc.write( 5, hour / 10);
memory::cartrtc.write( 6, day % 10);
memory::cartrtc.write( 7, day / 10);
memory::cartrtc.write( 8, month);
memory::cartrtc.write( 9, year % 10);
memory::cartrtc.write(10, (year / 10) % 10);
memory::cartrtc.write(11, year / 100);
memory::cartrtc.write(12, weekday % 7);
}
memory::cartrtc.write(16, current_time);
memory::cartrtc.write(17, current_time >> 8);
memory::cartrtc.write(18, current_time >> 16);
memory::cartrtc.write(19, current_time >> 24);
}
//returns day of week for specified date
//eg 0 = Sunday, 1 = Monday, ... 6 = Saturday
//usage: weekday(2008, 1, 1) returns weekday of January 1st, 2008
unsigned SRTC::weekday(unsigned year, unsigned month, unsigned day) {
unsigned y = 1900, m = 1; //epoch is 1900-01-01
unsigned sum = 0; //number of days passed since epoch
year = max(1900, year);
month = max(1, min(12, month));
day = max(1, min(31, day));
while(y < year) {
bool leapyear = false;
if((y % 4) == 0) {
leapyear = true;
if((y % 100) == 0 && (y % 400) != 0) leapyear = false;
}
sum += leapyear ? 366 : 365;
y++;
}
while(m < month) {
unsigned days = months[m - 1];
if(days == 28) {
bool leapyear = false;
if((y % 4) == 0) {
leapyear = true;
if((y % 100) == 0 && (y % 400) != 0) leapyear = false;
}
if(leapyear) days++;
}
sum += days;
m++;
}
sum += day - 1;
return (sum + 1) % 7; //1900-01-01 was a Monday
}
uint8 SRTC::mmio_read(uint addr) {
addr &= 0xffff;
if(addr == 0x2800) {
if(rtc_mode != RTCM_Read) return 0x00;
if(rtc_index < 0) {
update_time();
rtc_index++;
return 0x0f;
} else if(rtc_index > 12) {
rtc_index = -1;
return 0x0f;
} else {
return memory::cartrtc.read(rtc_index++);
}
}
return cpu.regs.mdr;
}
void SRTC::mmio_write(uint addr, uint8 data) {
addr &= 0xffff;
if(addr == 0x2801) {
data &= 0x0f; //only the low four bits are used
if(data == 0x0d) {
rtc_mode = RTCM_Read;
rtc_index = -1;
return;
}
if(data == 0x0e) {
rtc_mode = RTCM_Command;
return;
}
if(data == 0x0f) return; //unknown behavior
if(rtc_mode == RTCM_Write) {
if(rtc_index >= 0 && rtc_index < 12) {
memory::cartrtc.write(rtc_index++, data);
if(rtc_index == 12) {
//day of week is automatically calculated and written
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
unsigned month = memory::cartrtc.read( 8);
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
year += 1000;
memory::cartrtc.write(rtc_index++, weekday(year, month, day));
}
}
} else if(rtc_mode == RTCM_Command) {
if(data == 0) {
rtc_mode = RTCM_Write;
rtc_index = 0;
} else if(data == 4) {
rtc_mode = RTCM_Ready;
rtc_index = -1;
for(unsigned i = 0; i < 13; i++) memory::cartrtc.write(i, 0);
} else {
//unknown behavior
rtc_mode = RTCM_Ready;
}
}
}
}
SRTC::SRTC() {
}

View File

@@ -1,52 +1,22 @@
class SRTC : public MMIO {
public:
enum { MAX_SRTC_INDEX = 0x0c };
enum {
SRTC_READ = 0,
SRTC_WRITE,
SRTC_COMMAND,
SRTC_READY
};
enum {
SRTC_COMMAND_WRITE = 0,
SRTC_COMMAND_CLEAR = 4
};
/******************************
[srtc.data structure]
Index Description Range
----- ----------- -----
0 Seconds low 0-9
1 Seconds high 0-5
2 Minutes low 0-9
3 Minutes high 0-5
4 Hour low 0-9
5 Hour high 0-2
6 Day low 0-9
7 Day high 0-3
8 Month 1-12
9 Year ones 0-9
10 Year tens 0-9
11 Year hundreds 9-11 (9=19xx, 10=20xx, 11=21xx)
12 Day of week 0-6 (0=Sunday, ...)
******************************/
struct {
int8 index;
uint8 mode;
uint8 data[MAX_SRTC_INDEX + 1];
} srtc;
void set_time();
void init();
void enable();
void power();
void reset();
uint8 mmio_read (uint addr);
void mmio_write(uint addr, uint8 data);
SRTC();
};
extern SRTC srtc;
class SRTC : public MMIO {
public:
void update_time();
unsigned weekday(unsigned year, unsigned month, unsigned day);
void init();
void enable();
void power();
void reset();
uint8 mmio_read (uint addr);
void mmio_write(uint addr, uint8 data);
SRTC();
private:
static const unsigned months[12];
enum RTC_Mode { RTCM_Ready, RTCM_Command, RTCM_Read, RTCM_Write } rtc_mode;
signed rtc_index;
};
extern SRTC srtc;

View File

@@ -44,8 +44,9 @@ string file_updatepath(const char *req_file, const char *req_path) {
return path;
}
string_setting Path::base("path.base",
"Path that bsnes resides in", "");
string_setting Path::base("path.base", "Path that bsnes resides in", "");
string_setting Path::user("path.user", "Path to user folder", "");
string_setting Path::rom(config(), "path.rom",
"Default path to look for ROM files in (\"\" = use default directory)", "");
string_setting Path::patch(config(), "path.patch",

View File

@@ -10,7 +10,7 @@ extern struct File {
} file;
extern struct Path {
static string_setting base, rom, patch, save, cheat;
static string_setting base, user, rom, patch, save, cheat;
static string_setting bsx, st;
} path;

View File

@@ -1,19 +1,32 @@
template<int mask>
struct CPUFlag {
uint8 &data;
inline operator bool() const { return data & mask; }
inline CPUFlag& operator=(bool i) { data = (data & ~mask) | (-i & mask); return *this; }
CPUFlag(uint8 &data_) : data(data_) {}
};
class CPURegFlags {
public:
union {
uint8 data;
struct {
bool order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1);
};
};
public:
uint8 data;
CPUFlag<0x80> n;
CPUFlag<0x40> v;
CPUFlag<0x20> m;
CPUFlag<0x10> x;
CPUFlag<0x08> d;
CPUFlag<0x04> i;
CPUFlag<0x02> z;
CPUFlag<0x01> c;
inline operator unsigned() const { return data; }
template<typename T> inline unsigned operator = (const T i) { data = i; return data; }
template<typename T> inline unsigned operator |= (const T i) { data |= i; return data; }
template<typename T> inline unsigned operator ^= (const T i) { data ^= i; return data; }
template<typename T> inline unsigned operator &= (const T i) { data &= i; return data; }
inline unsigned operator = (unsigned i) { data = i; return data; }
inline unsigned operator |= (unsigned i) { data |= i; return data; }
inline unsigned operator ^= (unsigned i) { data ^= i; return data; }
inline unsigned operator &= (unsigned i) { data &= i; return data; }
CPURegFlags() : data(0) {}
CPURegFlags() : data(0), n(data), v(data), m(data), x(data), d(data), i(data), z(data), c(data) {}
};
class CPUReg16 {
@@ -24,17 +37,17 @@ public:
};
inline operator unsigned() const { return w; }
template<typename T> inline unsigned operator = (const T i) { w = i; return w; }
template<typename T> inline unsigned operator |= (const T i) { w |= i; return w; }
template<typename T> inline unsigned operator ^= (const T i) { w ^= i; return w; }
template<typename T> inline unsigned operator &= (const T i) { w &= i; return w; }
template<typename T> inline unsigned operator <<= (const T i) { w <<= i; return w; }
template<typename T> inline unsigned operator >>= (const T i) { w >>= i; return w; }
template<typename T> inline unsigned operator += (const T i) { w += i; return w; }
template<typename T> inline unsigned operator -= (const T i) { w -= i; return w; }
template<typename T> inline unsigned operator *= (const T i) { w *= i; return w; }
template<typename T> inline unsigned operator /= (const T i) { w /= i; return w; }
template<typename T> inline unsigned operator %= (const T i) { w %= i; return w; }
inline unsigned operator = (unsigned i) { w = i; return w; }
inline unsigned operator |= (unsigned i) { w |= i; return w; }
inline unsigned operator ^= (unsigned i) { w ^= i; return w; }
inline unsigned operator &= (unsigned i) { w &= i; return w; }
inline unsigned operator <<= (unsigned i) { w <<= i; return w; }
inline unsigned operator >>= (unsigned i) { w >>= i; return w; }
inline unsigned operator += (unsigned i) { w += i; return w; }
inline unsigned operator -= (unsigned i) { w -= i; return w; }
inline unsigned operator *= (unsigned i) { w *= i; return w; }
inline unsigned operator /= (unsigned i) { w /= i; return w; }
inline unsigned operator %= (unsigned i) { w %= i; return w; }
CPUReg16() : w(0) {}
};
@@ -48,17 +61,17 @@ public:
};
inline operator unsigned() const { return d; }
template<typename T> inline unsigned operator = (const T i) { d = uclip<24>(i); return d; }
template<typename T> inline unsigned operator |= (const T i) { d = uclip<24>(d | i); return d; }
template<typename T> inline unsigned operator ^= (const T i) { d = uclip<24>(d ^ i); return d; }
template<typename T> inline unsigned operator &= (const T i) { d = uclip<24>(d & i); return d; }
template<typename T> inline unsigned operator <<= (const T i) { d = uclip<24>(d << i); return d; }
template<typename T> inline unsigned operator >>= (const T i) { d = uclip<24>(d >> i); return d; }
template<typename T> inline unsigned operator += (const T i) { d = uclip<24>(d + i); return d; }
template<typename T> inline unsigned operator -= (const T i) { d = uclip<24>(d - i); return d; }
template<typename T> inline unsigned operator *= (const T i) { d = uclip<24>(d * i); return d; }
template<typename T> inline unsigned operator /= (const T i) { d = uclip<24>(d / i); return d; }
template<typename T> inline unsigned operator %= (const T i) { d = uclip<24>(d % i); return d; }
inline unsigned operator = (unsigned i) { d = uclip<24>(i); return d; }
inline unsigned operator |= (unsigned i) { d = uclip<24>(d | i); return d; }
inline unsigned operator ^= (unsigned i) { d = uclip<24>(d ^ i); return d; }
inline unsigned operator &= (unsigned i) { d = uclip<24>(d & i); return d; }
inline unsigned operator <<= (unsigned i) { d = uclip<24>(d << i); return d; }
inline unsigned operator >>= (unsigned i) { d = uclip<24>(d >> i); return d; }
inline unsigned operator += (unsigned i) { d = uclip<24>(d + i); return d; }
inline unsigned operator -= (unsigned i) { d = uclip<24>(d - i); return d; }
inline unsigned operator *= (unsigned i) { d = uclip<24>(d * i); return d; }
inline unsigned operator /= (unsigned i) { d = uclip<24>(d / i); return d; }
inline unsigned operator %= (unsigned i) { d = uclip<24>(d % i); return d; }
CPUReg24() : d(0) {}
};
@@ -70,6 +83,6 @@ public:
CPURegFlags p;
uint8 db;
uint8 mdr;
bool e;
CPURegs() : db(0), mdr(0x00), e(false) {}
bool e;
CPURegs() : db(0), mdr(0), e(false) {}
};

View File

@@ -2,210 +2,204 @@
//op_read
inline void sCPU::op_adc_b() {
int32 r = regs.a.l + rd.l + regs.p.c;
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 += ((rd.l) & 15) + regs.p.c;
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 += (rd.l & 15) + regs.p.c;
if(n0 > 9) {
n0 -= 10;
n0 &= 15;
n0 = (n0 - 10) & 15;
n1++;
}
n1 += ((rd.l >> 4) & 15);
if(n1 > 9) {
n1 -= 10;
n1 &= 15;
n1 = (n1 - 10) & 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n1 << 4) | (n0);
r = (n1 << 4) | n0;
} else {
r = regs.a.l + rd.l + regs.p.c;
regs.p.c = (r > 0xff);
regs.p.c = r > 0xff;
}
regs.p.n = !!(r & 0x80);
regs.p.v = !!(~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.n = r & 0x80;
regs.p.v = ~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80;
regs.p.z = (uint8)r == 0;
regs.a.l = r;
}
inline void sCPU::op_adc_w() {
int32 r;
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 += ((rd.w) & 15) + regs.p.c;
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 += (rd.w & 15) + regs.p.c;
if(n0 > 9) {
n0 -= 10;
n0 &= 15;
n0 = (n0 - 10) & 15;
n1++;
}
n1 += ((rd.w >> 4) & 15);
if(n1 > 9) {
n1 -= 10;
n1 &= 15;
n1 = (n1 - 10) & 15;
n2++;
}
n2 += ((rd.w >> 8) & 15);
if(n2 > 9) {
n2 -= 10;
n2 &= 15;
n2 = (n2 - 10) & 15;
n3++;
}
n3 += ((rd.w >> 12) & 15);
if(n3 > 9) {
n3 -= 10;
n3 &= 15;
n3 = (n3 - 10) & 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | n0;
} else {
r = regs.a.w + rd.w + regs.p.c;
regs.p.c = (r > 0xffff);
regs.p.c = r > 0xffff;
}
regs.p.n = !!(r & 0x8000);
regs.p.v = !!(~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.n = r & 0x8000;
regs.p.v = ~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000;
regs.p.z = (uint16)r == 0;
regs.a.w = r;
}
inline void sCPU::op_and_b() {
regs.a.l &= rd.l;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void sCPU::op_and_w() {
regs.a.w &= rd.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void sCPU::op_bit_b() {
regs.p.n = !!(rd.l & 0x80);
regs.p.v = !!(rd.l & 0x40);
regs.p.z = ((rd.l & regs.a.l) == 0);
regs.p.n = rd.l & 0x80;
regs.p.v = rd.l & 0x40;
regs.p.z = (rd.l & regs.a.l) == 0;
}
inline void sCPU::op_bit_w() {
regs.p.n = !!(rd.w & 0x8000);
regs.p.v = !!(rd.w & 0x4000);
regs.p.z = ((rd.w & regs.a.w) == 0);
regs.p.n = rd.w & 0x8000;
regs.p.v = rd.w & 0x4000;
regs.p.z = (rd.w & regs.a.w) == 0;
}
inline void sCPU::op_cmp_b() {
int32 r = regs.a.l - rd.l;
regs.p.n = !!(r & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r >= 0);
int r = regs.a.l - rd.l;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
}
inline void sCPU::op_cmp_w() {
int32 r = regs.a.w - rd.w;
regs.p.n = !!(r & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.c = (r >= 0);
int r = regs.a.w - rd.w;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
}
inline void sCPU::op_cpx_b() {
int32 r = regs.x.l - rd.l;
regs.p.n = !!(r & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r >= 0);
int r = regs.x.l - rd.l;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
}
inline void sCPU::op_cpx_w() {
int32 r = regs.x.w - rd.w;
regs.p.n = !!(r & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.c = (r >= 0);
int r = regs.x.w - rd.w;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
}
inline void sCPU::op_cpy_b() {
int32 r = regs.y.l - rd.l;
regs.p.n = !!(r & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r >= 0);
int r = regs.y.l - rd.l;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
}
inline void sCPU::op_cpy_w() {
int32 r = regs.y.w - rd.w;
regs.p.n = !!(r & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.c = (r >= 0);
int r = regs.y.w - rd.w;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
}
inline void sCPU::op_eor_b() {
regs.a.l ^= rd.l;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void sCPU::op_eor_w() {
regs.a.w ^= rd.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void sCPU::op_lda_b() {
regs.a.l = rd.l;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void sCPU::op_lda_w() {
regs.a.w = rd.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void sCPU::op_ldx_b() {
regs.x.l = rd.l;
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
regs.p.n = regs.x.l & 0x80;
regs.p.z = regs.x.l == 0;
}
inline void sCPU::op_ldx_w() {
regs.x.w = rd.w;
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
regs.p.n = regs.x.w & 0x8000;
regs.p.z = regs.x.w == 0;
}
inline void sCPU::op_ldy_b() {
regs.y.l = rd.l;
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
regs.p.n = regs.y.l & 0x80;
regs.p.z = regs.y.l == 0;
}
inline void sCPU::op_ldy_w() {
regs.y.w = rd.w;
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
regs.p.n = regs.y.w & 0x8000;
regs.p.z = regs.y.w == 0;
}
inline void sCPU::op_ora_b() {
regs.a.l |= rd.l;
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void sCPU::op_ora_w() {
regs.a.w |= rd.w;
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void sCPU::op_sbc_b() {
int32 r;
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 -= ((rd.l ) & 15) + !regs.p.c;
n1 -= ((rd.l >> 4) & 15);
if(n0 > 9) {
@@ -221,21 +215,21 @@ int32 r;
r = (n1 << 4) | (n0);
} else {
r = regs.a.l - rd.l - !regs.p.c;
regs.p.c = (r >= 0);
regs.p.c = r >= 0;
}
regs.p.n = !!(r & 0x80);
regs.p.v = !!((regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.n = r & 0x80;
regs.p.v = (regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80;
regs.p.z = (uint8)r == 0;
regs.a.l = r;
}
inline void sCPU::op_sbc_w() {
int32 r;
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 -= ((rd.w ) & 15) + !regs.p.c;
n1 -= ((rd.w >> 4) & 15);
n2 -= ((rd.w >> 8) & 15);
@@ -261,116 +255,116 @@ int32 r;
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
} else {
r = regs.a.w - rd.w - !regs.p.c;
regs.p.c = (r >= 0);
regs.p.c = r >= 0;
}
regs.p.n = !!(r & 0x8000);
regs.p.v = !!((regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.n = r & 0x8000;
regs.p.v = (regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000;
regs.p.z = (uint16)r == 0;
regs.a.w = r;
}
//op_rmw
inline void sCPU::op_inc_b() {
rd.l++;
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void sCPU::op_inc_w() {
rd.w++;
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void sCPU::op_dec_b() {
rd.l--;
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void sCPU::op_dec_w() {
rd.w--;
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void sCPU::op_asl_b() {
regs.p.c = !!(rd.l & 0x80);
regs.p.c = rd.l & 0x80;
rd.l <<= 1;
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void sCPU::op_asl_w() {
regs.p.c = !!(rd.w & 0x8000);
regs.p.c = rd.w & 0x8000;
rd.w <<= 1;
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void sCPU::op_lsr_b() {
regs.p.c = rd.l & 1;
rd.l >>= 1;
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void sCPU::op_lsr_w() {
regs.p.c = rd.w & 1;
rd.w >>= 1;
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void sCPU::op_rol_b() {
uint16 carry = (uint16)regs.p.c;
regs.p.c = !!(rd.l & 0x80);
unsigned carry = (unsigned)regs.p.c;
regs.p.c = rd.l & 0x80;
rd.l = (rd.l << 1) | carry;
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void sCPU::op_rol_w() {
uint16 carry = (uint16)regs.p.c;
regs.p.c = !!(rd.w & 0x8000);
unsigned carry = (unsigned)regs.p.c;
regs.p.c = rd.w & 0x8000;
rd.w = (rd.w << 1) | carry;
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void sCPU::op_ror_b() {
uint16 carry = (uint16)regs.p.c << 7;
unsigned carry = (unsigned)regs.p.c << 7;
regs.p.c = rd.l & 1;
rd.l = carry | (rd.l >> 1);
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void sCPU::op_ror_w() {
uint16 carry = (uint16)regs.p.c << 15;
unsigned carry = (unsigned)regs.p.c << 15;
regs.p.c = rd.w & 1;
rd.w = carry | (rd.w >> 1);
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void sCPU::op_trb_b() {
regs.p.z = ((rd.l & regs.a.l) == 0);
regs.p.z = (rd.l & regs.a.l) == 0;
rd.l &= ~regs.a.l;
}
inline void sCPU::op_trb_w() {
regs.p.z = ((rd.w & regs.a.w) == 0);
regs.p.z = (rd.w & regs.a.w) == 0;
rd.w &= ~regs.a.w;
}
inline void sCPU::op_tsb_b() {
regs.p.z = ((rd.l & regs.a.l) == 0);
regs.p.z = (rd.l & regs.a.l) == 0;
rd.l |= regs.a.l;
}
inline void sCPU::op_tsb_w() {
regs.p.z = ((rd.w & regs.a.w) == 0);
regs.p.z = (rd.w & regs.a.w) == 0;
rd.w |= regs.a.w;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -2,39 +2,40 @@ static char enc_icon48[] = {
"_gAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHw"
"AfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB"
"8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHw"
"AfAB8AHwAfD_AfAB8AHwAfAB8AHwAfABgFD_oRYPBAA1BABWVQQAWwQAQQQAGgQA"
"Av8u8AHwAfAB8AHwAfAB8AHwVbSAAQQALQQAsAQA9FUEAP8EwPsEAM4EAFP9BAAE"
"QvAB8AHwAfAB8AHwqwHwvOAEBACFBAD5uPDVBOD-BAC9BAAUSvAB8L8B8AHwAfAB"
"8AHwvGADBACuoqjwBPAEwNsEABZS8H8B8AHwAfAB8AHwAfDAIHuvnPAE8ATwBCDH"
"BAAFVvC_AfAB8AHwAfAB8LzAIAQA3vaY8ATwBPAEYGZa8AHw3wHwAfAB8AHwwMCX"
"kPAE8OsE8ASg3wQABl7wAfAB8K8B8AHwAfC8QAYEAOeQ8PcE8ATw0OMvYvAB8AHw"
"AfDXAfAB8MBAHAQA_JDwBPALBPAE4GRi8AAAPz9U_wEEAA0EAB0EAB59BAAPBABE"
"9gHwAfDA8BVVBABxBAB3BAChUET9p5zwBPAE8BaGuMALBACqbAQAzgQA9AQA-wQA"
"qvwEAPYEANYEAHoEAL4SlvAB8AHwAfAEhjIEAF68FEKo8ATwBFCBcIFHtQQA5AQA"
"_wTwBKDuBAB-XDQQjvAB8AHwAfAQhmhHzPYE8ARgpQ5YwEBor2xBsPAE8AQQ_QQA"
"hFTyfwHwAfAB8MjA-Bgg8wTQowAQ-_-rACMuNrz_SrzwBPAE8MQgZ4LwbwHwAfAB"
"8BDJkbTwBMCnAAfLfV-0ETU6fP_mnPAE8ATwBCAkExxfhvAB8AHwAfDEgBEEAO0D"
"uPAEQKQO_f-tAIBCLDX_cTw-mPA3BPAE8ASAlYLwAUDNAKoBBAAFBAAUBAAiBAB-"
"JQhAEBAYEETz5PYE8KgABZxKRfIENju8_9eQ8ATwBPAEoOq0wKoDBAAsBACGBADM"
"BADq7AQA_AQA_gSAEBAYEOrKBACDBAAqBABMo6gAFkC88AQgrvgCBy83wP8VPj7_"
"-JDwBPCvBPAIs7yAuBDEoED_BPBXBPAEQDAQwAQAKcCAHRf8S7hQMBl_uFk4O_--"
"KYzwBPAE8ATwvEBhBABe95zwBPAE8ARg9gQAW1HAIJ8XFKwA8uhIkFUEAB-sxhkE"
"AH0EAJL1BADDBADznPAE8ATwwADozQBIBAD5kPAE8ATwAQTg-ADQACn_nrwYAshD"
"pPUB8NAQEQQA3nGgRqjwBPDAkOKI8ATw9wTwBPAEIM8UAwHwAfAB8HvIEPQYzKjw"
"BPAEQDQS0t-I8ATwBPAE8ARAeprwAfB3AfDEYLAZyqzwBPAEAMX1cAAvBADxiPAE"
"8ATwBOB68AQAGZbwAfAB8MSgHK0EAPGw8ASg_gQAScBDvj4URZTwBPAE8AQw6gQA"
"RjwN9mwJ__8IBAAT_QQAGgRADBAUEET2xHDgE6u48ARwuwQAA0CFGQQAup0EAPOc"
"8ATwBIDyBACgmADLABe0gAkEAKpFBACaBADSBADsBABa-QQA-wRADBDtBADTVQQA"
"nQQASAQACsDAGK0EAPW48AQg3QQAFfbwVcggEQQAUwQAoRxD6b0EAPRcJNwwEBAY"
"EJ8EAKpRBAAQuIAGBABuBAC66AQA_wTwBPAEgOoEAEpzBAAHSxBBOFgryF-88BQg"
"LHEB8NDQBgQAC10EAA0IQLj-vDAQBADFr5jwBPAE8ASgywQAFMRA6pm4gOcEAHAE"
"AOAgAfCvAfAB8AHwvEACBAC1jPAvBPAE8ATwBAC_VBBDMtT_TrAAeQQAPAQAYKLf"
"AfAB8AHwAfDAQBnYQozw1wTwBPAE8P0EAB1p8AHwrwHwAfAB8MDgGAQA-ojw7wTw"
"BPAE8AQA_AQA3PsB8N8B8AHwAfDA8CQVsYjwBPD3BPAE8AQAulz1AfAB8AHw1wHw"
"AfDEQA0EAL2M8ATw9wTwBKAEFBFh8AHwAfAB8FcB8AHwxIAFBABoBADjXQQA_pzw"
"BPAEgOUEAG3_hCUB8AHwAfAB8AHwAfAB8KvIEFwXPQQAkgQAz8BGXveYQwQQDBAU"
"ENAEAJT9BABB9CYB8AHwAfAB8AHwrwHwAfAB8NBwBAQADtgl_QQwDxRA5PIB8AHw"
"AfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB"
"8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHw"
"AfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHwfwHwAfAB8AHwAfAB8AGA"
"AfAB8AHwAfD_AfAB8AHwAfAB8AHwAfABAAD_qgAD_p8VOwD_oRaI_qEWthD-oBbL"
"CADE_qEAFaP_oBZm_p38GBU28AHwAfAB8AHwAfBfAfAB8AFQuBCoAMe0AP4twAD_"
"BPAEIPAkAIX_-JkZCkLwAfAB8AHwAfBHAfAB8HSB_wABtABvPQQA-7DwBPAEECwA"
"0P74oBIbTvAB8AHwAfAB8EcB8AHweEGgFWwkAv0HqPAE8MSwFdX-oRr-E1LwAfAB"
"8AHwAfAB8Lzg6KEUMRAC96DwBPAE8P3EIKXAEVrwAfAB8AHwAfDzAfDAsBa3mPAE"
"8ATwwED_uAE4E1rwAfAB8AHwAfAB8PG8YKIVJDjyBPAE8ATA-KAWoF7wAfAB8AHw"
"AfB7AfD4gmmQ8ATwBPDM4-Z_XvAB8AHwAfAB8AHwwICPH_wSePQE8ATwBMClDxEB"
"YNBERP8PPz_-oEw-Pv56CACMCACCgggAXT8__yD2BA808wHwAfDAkKMSDv6AmxwS"
"_qQYH8QC6kjIAJTUAOug8ATwhOFDRABYUDw8_hWsAI9QPj7_8KwA_wTw_oL6BAC1"
"PT3-MpbwjwHwAfAB8AxmpRkUFAOOkxjzBPAEoJ8PEEAQdZQAOrwA47TwBPAoAPh9"
"yAB0hvAB8AHwAfBcsha6XFwC-KzwBPDsAOQ0EHWQAD0EAPSs8ATwBMCAn4LwAfAB"
"8AHwXLUVakz4gwTwKACbQkL-F0wBTuac8ATwiPH-_AQATh-C8AHwAfAB8ExifwAC"
"DcAAtbTwfKT8_qETejSAAJOc8ATwBPAUY9p9CAAIhvAB8AHwAfCEYZ4MGDWE8YCn"
"nEs8_3oRgAD1lPAE8ATwBKBVh4LwAQAUCwDNACQEAKBNAMwAaggAewgAoH8AywBz"
"CABbCABgNwDIAA458Nxp2IO88Hwhzf-ZEQ-0A15XjPAE8ATwhOGlfaDOVAA1oACY"
"sADhCAD9jQgA_wTwBEDMAPQEAHq7NABjCAAcq2QRvPAW9sUMXHwAiIzwBPAE8MDg"
"otZxIMsAGYQArQQATv6s8ATwzPAA4wQAUVcKAGQmYAR9MILpBAB3sP-qKgbgUPwC"
"mwQAevuAAP6U8ATwBPDAYO3QANEAHIQA3JjwBPCrBPAEoPwEAGyAQVRwAeCV_qIX"
"WPQWZNJ8AKoQgAQbSAI2hABtzAC6xAgA_aDwBPCIxOc4Ab6mjPAE8ATwBPAEAPYE"
"AK9YZwHwAfA2QwLAAEgEAK7dqPAE8MCAx8AA5Ijw_wTwBPAE8ExCFPQB8AHwAQDQ"
"Q0P-E5QAw6zwBPD1wECLcAC2iPAE8ATwBPD1BAD70AMqmvAB8AHwATDQODj-EpgA"
"1LDwxPbFBAAxcCDNAOyM8ATwewTwBOCGkvAB8AHwIOM8t-AzuPC8g66UasQwyJDw"
"VwTwBPAEIPHEBG4KAAJBDcYKAP7-LAQAT1UEAGUEAHAEAGoEAFd1BAA5BAASJAAY"
"-8Qg_gaytPB8Yeg7O_8eUTGgvwAEyABUUAK3XZAA9aTw6OJsFdgIAIOQAM8AG_11"
"_guUAKpgCAC1BADvDAD_BPAxBED-_vgIAEoA_nzDBAD4o0BA_lO88Lwgjuy4FPLw"
"AYDPABCYAKpCoABtBACKBACbEACKngQAk4wnzQBXoCd3qBe5plgh4azwBPDM8P76"
"9QQAiwwA1CjgGeQSvMD6yAQAKbHwAfAB8AHwvMC9RBH-nPAE8ATwBKDAxCFVVDXu"
"sADzCAC9dEgEX3nwAfAB8AHwvMAxBAD8X4zwBPAE8ATwTAB-3Ewh_bQADHHwAfAB"
"8AHwAfDAYL50iPAE8ATwBPDAQMRl8L8B8AHwAfAB8AHwcABMiPDvBPAE8ATwwECc"
"ZfAB8AHwrwHwAfAB8HQAAnQAsIzw9wTwBPC84OQIABy1AfAB8O8B8AHwAfDs1ZUI"
"8wTwBPD1vGDHBAAkXfAB8AHwAfCnAfAB8Mjw_zCEAJ8EAK7rpPAE8CgA9wQAvAQA"
"_lQQAJC1AfAB8AHwAfAB8FcB8MjwkBE6BABsBACPVQQApAQArwQAqQQAl_UgAHgI"
"AEsEANQsAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB"
"8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_"
"AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHw"
"AfD_AfAB8AHwAfAB8AHwAfAB8A8B8AHwAfABsA"
};

View File

@@ -1,5 +1,5 @@
/*
bbase : version 0.13 ~byuu (2008-04-02)
bbase : version 0.14 ~byuu (2008-04-16)
license: public domain
*/
@@ -99,37 +99,12 @@ static char *userpath(char *output) {
#else
static char *userpath(char *output) {
strcpy(output, "."); //failsafe
struct passwd *userinfo = getpwuid(getuid());
struct passwd *userinfo = getpwuid(getuid());
if(userinfo) { strcpy(output, userinfo->pw_dir); }
return output;
}
#endif
/*****
* template functions
*****/
template<typename T> inline void safe_free(T &handle) {
if(handle) {
free(handle);
handle = 0;
}
}
template<typename T> inline void safe_delete(T &handle) {
if(handle) {
delete handle;
handle = 0;
}
}
template<typename T> inline void safe_release(T &handle) {
if(handle) {
handle->Release();
handle = 0;
}
}
template<int min, int max, typename T> inline T minmax(const T x) {
return (x < (T)min) ? (T)min : (x > (T)max) ? (T)max : x;
}
@@ -177,47 +152,47 @@ template<int min, int max, typename T> inline T minmax(const T x) {
*****/
//pseudo-random number generator
static uint prng() {
static uint n = 0;
static unsigned prng() {
static unsigned n = 0;
return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320);
}
static uint64 fget(FILE *fp, uint length = 1) {
uint64 data = 0;
for(uint i = 0; i < length; i++) {
static uint64 fget(FILE *fp, unsigned length = 1) {
uint64 data = 0;
for(unsigned i = 0; i < length; i++) {
data |= fgetc(fp) << (i << 3);
}
return data;
}
static void fput(FILE *fp, uint64 data, uint length = 1) {
for(uint i = 0; i < length; i++) {
static void fput(FILE *fp, uint64 data, unsigned length = 1) {
for(unsigned i = 0; i < length; i++) {
fputc(data >> (i << 3), fp);
}
}
static bool fexists(const char *fn) {
FILE *fp = fopen(fn, "rb");
if(!fp)return false;
FILE *fp = fopen(fn, "rb");
if(!fp) return false;
fclose(fp);
fp = 0;
return true;
}
static uint32 fsize(FILE *fp) {
if(!fp)return 0;
uint32 pos = ftell(fp);
static unsigned fsize(FILE *fp) {
if(!fp) return 0;
unsigned pos = ftell(fp);
fseek(fp, 0, SEEK_END);
uint32 size = ftell(fp);
unsigned size = ftell(fp);
fseek(fp, pos, SEEK_SET);
return size;
}
static uint32 fsize(const char *fn) {
FILE *fp = fopen(fn, "rb");
if(!fp)return 0;
static unsigned fsize(const char *fn) {
FILE *fp = fopen(fn, "rb");
if(!fp) return 0;
fseek(fp, 0, SEEK_END);
uint32 size = ftell(fp);
unsigned size = ftell(fp);
fclose(fp);
fp = 0;
return size;

6
src/lib/hiro/cc.bat Normal file
View File

@@ -0,0 +1,6 @@
mingw32-g++ -c test/test.cpp -I. -I../
mingw32-g++ -c hiro.cpp -I. -I../
mingw32-g++ -c ../nall/string.cpp -I. -I../
mingw32-g++ test.o hiro.o string.o -o test_app.exe -lkernel32 -luser32 -lgdi32 -ladvapi32 -lcomctl32 -lcomdlg32
@pause
@del *.o

6
src/lib/hiro/cc.sh Normal file
View File

@@ -0,0 +1,6 @@
clear
g++ -c test/test.cpp -I. -I../
g++ -c hiro.cpp `pkg-config --cflags gtk+-2.0` -I. -I../
g++ -c ../nall/string.cpp -I. -I../
g++ test.o hiro.o string.o -o test_app `pkg-config --libs gtk+-2.0` -lXtst
rm *.o

View File

@@ -4,6 +4,7 @@ void hiro_pbutton_tick(pButton *p) {
void pButton::create(uint style, uint width, uint height, const char *text) {
button = gtk_button_new_with_label(text ? text : "");
set_default_font(button);
gtk_widget_set_size_request(button, width, height);
gtk_widget_show(button);
g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(hiro_pbutton_tick), (gpointer)this);

View File

@@ -1,9 +1,10 @@
void hiro_pcheckbox_tick(pCheckbox *p) {
if(p->self.on_tick) p->self.on_tick(Event(Event::Tick, p->checked(), &p->self));
if(!p->locked && p->self.on_tick) p->self.on_tick(Event(Event::Tick, p->checked(), &p->self));
}
void pCheckbox::create(uint style, uint width, uint height, const char *text) {
checkbox = gtk_check_button_new_with_label(text ? text : "");
set_default_font(checkbox);
gtk_widget_set_size_request(checkbox, width, height);
gtk_widget_show(checkbox);
g_signal_connect_swapped(G_OBJECT(checkbox), "toggled", G_CALLBACK(hiro_pcheckbox_tick), (gpointer)this);
@@ -15,7 +16,9 @@ void pCheckbox::set_text(const char *text) {
}
void pCheckbox::check(bool state) {
locked = true;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), state ? TRUE : FALSE);
locked = false;
}
void pCheckbox::uncheck() {
@@ -28,6 +31,7 @@ bool pCheckbox::checked() {
pCheckbox::pCheckbox(Checkbox &self_) : pFormControl(self_), self(self_) {
checkbox = 0;
locked = false;
}
/* internal */

View File

@@ -10,6 +10,7 @@ public:
pCheckbox(Checkbox&);
/* internal */
GtkWidget *checkbox;
GtkWidget* gtk_handle();
GtkWidget *checkbox;
bool locked;
};

View File

@@ -4,6 +4,7 @@ void hiro_pcombobox_change(pCombobox *p) {
void pCombobox::create(uint style, uint width, uint height, const char *text) {
combobox = gtk_combo_box_new_text();
set_default_font(combobox);
gtk_widget_set_size_request(combobox, width, height);
gtk_widget_show(combobox);

View File

@@ -8,12 +8,12 @@ void pEditbox::create(uint style, uint width, uint height, const char *text) {
gtk_widget_set_size_request(editbox, width, height);
gtk_widget_show(editbox);
} else {
GtkPolicyType hscroll = (style & Editbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS :
(style & Editbox::HorizontalScrollNever) ? GTK_POLICY_NEVER :
GTK_POLICY_AUTOMATIC;
GtkPolicyType vscroll = (style & Editbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS :
(style & Editbox::VerticalScrollNever) ? GTK_POLICY_NEVER :
GTK_POLICY_AUTOMATIC;
GtkPolicyType hscroll = (style & Editbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS :
(style & Editbox::HorizontalScrollNever) ? GTK_POLICY_NEVER :
GTK_POLICY_AUTOMATIC;
GtkPolicyType vscroll = (style & Editbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS :
(style & Editbox::VerticalScrollNever) ? GTK_POLICY_NEVER :
GTK_POLICY_AUTOMATIC;
scrollbox = gtk_scrolled_window_new(0, 0);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbox), hscroll, vscroll);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollbox), GTK_SHADOW_ETCHED_IN);
@@ -26,6 +26,8 @@ void pEditbox::create(uint style, uint width, uint height, const char *text) {
gtk_widget_show(editbox);
gtk_widget_show(scrollbox);
}
set_default_font(editbox);
}
void pEditbox::set_text(const char *text) {
@@ -38,10 +40,10 @@ void pEditbox::set_text(const char *text) {
uint pEditbox::get_text(char *text, uint length) {
if(multiline == false) {
const char *temp = gtk_entry_get_text(GTK_ENTRY(editbox));
const char *temp = gtk_entry_get_text(GTK_ENTRY(editbox));
return strlcpy(text, temp ? temp : "", length);
} else {
GtkTextIter start, end;
GtkTextIter start, end;
gtk_text_buffer_get_start_iter(buffer, &start);
gtk_text_buffer_get_end_iter(buffer, &end);
return strlcpy(text, gtk_text_buffer_get_text(buffer, &start, &end, true), length);

View File

@@ -1,5 +1,6 @@
void pFrame::create(uint style, uint width, uint height, const char *text) {
frame = gtk_frame_new(text ? text : "");
set_default_font(frame);
gtk_widget_set_size_request(frame, width, height);
gtk_widget_show(frame);
}

View File

@@ -6,6 +6,17 @@ using nall::max;
namespace libhiro {
static void set_font(GtkWidget *widget, gpointer font) {
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
if(GTK_IS_CONTAINER(widget)) {
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)set_font, font);
}
}
static void set_default_font(GtkWidget *widget) {
set_font(widget, phiro().font);
}
#include "keymap.cpp"
#include "widget.cpp"
#include "window.cpp"
@@ -49,9 +60,15 @@ void pHiro::init() {
} else {
colormap = gdk_screen_get_rgb_colormap(screen);
}
font = pango_font_description_new();
pango_font_description_set_family(font, "Sans");
pango_font_description_set_absolute_size(font, 11.0 * PANGO_SCALE);
pango_font_description_set_style(font, PANGO_STYLE_NORMAL);
}
void pHiro::term() {
pango_font_description_free(font);
enable_screensaver();
}

View File

@@ -55,6 +55,7 @@ public:
/* internal */
GdkScreen *screen;
GdkColormap *colormap;
PangoFontDescription *font;
bool is_composited;
char default_path[PATH_MAX];

View File

@@ -1,5 +1,6 @@
void pLabel::create(uint style, uint width, uint height, const char *text) {
label = gtk_label_new(text ? text : "");
set_default_font(label);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
gtk_widget_set_size_request(label, width, height);
gtk_widget_show(label);

View File

@@ -8,22 +8,22 @@ void hiro_plistbox_activate(pListbox *p) {
}
void pListbox::create(uint style, uint width, uint height, const char *columns, const char *text) {
bool header = style & Listbox::Header;
GtkPolicyType hscroll = (style & Listbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS :
(style & Listbox::HorizontalScrollNever) ? GTK_POLICY_NEVER :
GTK_POLICY_AUTOMATIC;
GtkPolicyType vscroll = (style & Listbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS :
(style & Listbox::VerticalScrollNever) ? GTK_POLICY_NEVER :
GTK_POLICY_AUTOMATIC;
bool header = style & Listbox::Header;
GtkPolicyType hscroll = (style & Listbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS :
(style & Listbox::HorizontalScrollNever) ? GTK_POLICY_NEVER :
GTK_POLICY_AUTOMATIC;
GtkPolicyType vscroll = (style & Listbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS :
(style & Listbox::VerticalScrollNever) ? GTK_POLICY_NEVER :
GTK_POLICY_AUTOMATIC;
scrollbox = gtk_scrolled_window_new(0, 0);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbox), hscroll, vscroll);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollbox), GTK_SHADOW_ETCHED_IN);
lstring list;
lstring list;
split(list, "\t", columns);
GType *v = (GType*)malloc(count(list) * sizeof(GType));
GType *v = (GType*)malloc(count(list) * sizeof(GType));
for(uint i = 0; i < count(list); i++) v[i] = G_TYPE_STRING;
store = gtk_list_store_newv(count(list), v);
free(v);
@@ -35,7 +35,7 @@ GType *v = (GType*)malloc(count(list) * sizeof(GType));
gtk_widget_show(listbox);
gtk_widget_show(scrollbox);
//alternate colors for each listbox entry if there are multiple columns ...
//alternate colors for each listbox entry if there are multiple columns ...
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(listbox), count(list) >= 2 ? true : false);
for(uint i = 0; i < count(list); i++) {
renderer = gtk_cell_renderer_text_new();
@@ -54,6 +54,8 @@ GType *v = (GType*)malloc(count(list) * sizeof(GType));
g_signal_connect_swapped(G_OBJECT(listbox), "cursor-changed", G_CALLBACK(hiro_plistbox_change), (gpointer)this);
g_signal_connect_swapped(G_OBJECT(listbox), "row-activated", G_CALLBACK(hiro_plistbox_activate), (gpointer)this);
set_default_font(listbox);
}
void pListbox::autosize_columns() {

View File

@@ -1,15 +1,18 @@
void hiro_pmenucheckitem_tick(pMenuCheckItem *p) {
if(p->self.on_tick) p->self.on_tick(Event(Event::Tick, p->checked(), &p->self));
if(!p->locked && p->self.on_tick) p->self.on_tick(Event(Event::Tick, p->checked(), &p->self));
}
void pMenuCheckItem::create(const char *text) {
item = gtk_check_menu_item_new_with_label(text ? text : "?");
set_default_font(item);
gtk_widget_show(item);
g_signal_connect_swapped(G_OBJECT(item), "toggled", G_CALLBACK(hiro_pmenucheckitem_tick), (gpointer)this);
}
void pMenuCheckItem::check(bool state) {
locked = true;
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), state ? TRUE : FALSE);
locked = false;
}
void pMenuCheckItem::uncheck() {
@@ -22,6 +25,7 @@ bool pMenuCheckItem::checked() {
pMenuCheckItem::pMenuCheckItem(MenuCheckItem &self_) : pMenuControl(self_), self(self_) {
item = 0;
locked = true;
}
/* internal */

View File

@@ -9,6 +9,7 @@ public:
pMenuCheckItem(MenuCheckItem&);
/* internal */
GtkWidget *item;
GtkWidget* gtk_handle();
GtkWidget *item;
bool locked;
};

View File

@@ -1,6 +1,7 @@
void pMenuGroup::create(const char *text) {
group = gtk_menu_new();
item = gtk_menu_item_new_with_label(text ? text : "");
set_default_font(item);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), group);
gtk_widget_show(item);
}

View File

@@ -4,6 +4,7 @@ void hiro_pmenuitem_tick(pMenuItem *p) {
void pMenuItem::create(const char *text) {
item = gtk_menu_item_new_with_label(text ? text : "");
set_default_font(item);
g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(hiro_pmenuitem_tick), (gpointer)this);
gtk_widget_show(item);
}

View File

@@ -1,7 +1,7 @@
void hiro_pmenuradioitem_tick(pMenuRadioItem *p) {
//GTK+ sends two messages: one for the activated radio item,
//and one for the deactivated radio item. ignore the latter.
if(p->checked() && p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self));
//GTK+ sends two messages: one for the activated radio item,
//and one for the deactivated radio item. ignore the latter.
if(!p->locked && p->checked() && p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self));
}
void pMenuRadioItem::create(MenuRadioItemGroup &group, const char *text) {
@@ -10,12 +10,15 @@ void pMenuRadioItem::create(MenuRadioItemGroup &group, const char *text) {
} else {
item = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(group[0]->p.gtk_handle()), text ? text : "");
}
set_default_font(item);
gtk_widget_show(item);
g_signal_connect_swapped(G_OBJECT(item), "toggled", G_CALLBACK(hiro_pmenuradioitem_tick), (gpointer)this);
}
void pMenuRadioItem::check() {
locked = true;
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
locked = false;
}
bool pMenuRadioItem::checked() {
@@ -24,6 +27,7 @@ bool pMenuRadioItem::checked() {
pMenuRadioItem::pMenuRadioItem(MenuRadioItem &self_) : pMenuControl(self_), self(self_) {
item = 0;
locked = false;
}
/* internal */

View File

@@ -8,6 +8,7 @@ public:
pMenuRadioItem(MenuRadioItem&);
/* internal */
GtkWidget *item;
GtkWidget* gtk_handle();
GtkWidget *item;
bool locked;
};

View File

@@ -1,7 +1,7 @@
void hiro_pradiobox_tick(pRadiobox *p) {
//GTK+ sends two messages: one for the activated radiobox,
//and one for the deactivated radiobox. ignore the latter.
if(p->checked() && p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self));
//GTK+ sends two messages: one for the activated radiobox,
//and one for the deactivated radiobox. ignore the latter.
if(!p->locked && p->checked() && p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self));
}
void pRadiobox::create(RadioboxGroup &group, uint style, uint width, uint height, const char *text) {
@@ -10,6 +10,7 @@ void pRadiobox::create(RadioboxGroup &group, uint style, uint width, uint height
} else {
radiobox = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(group[0]->p.gtk_handle()), text ? text : "");
}
set_default_font(radiobox);
gtk_widget_set_size_request(radiobox, width, height);
gtk_widget_show(radiobox);
g_signal_connect_swapped(G_OBJECT(radiobox), "toggled", G_CALLBACK(hiro_pradiobox_tick), (gpointer)this);
@@ -21,7 +22,9 @@ void pRadiobox::set_text(const char *text) {
}
void pRadiobox::check() {
locked = true;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radiobox), TRUE);
locked = false;
}
bool pRadiobox::checked() {
@@ -30,6 +33,7 @@ bool pRadiobox::checked() {
pRadiobox::pRadiobox(Radiobox &self_) : pFormControl(self), self(self_) {
radiobox = 0;
locked = false;
}
/* internal */

View File

@@ -9,6 +9,7 @@ public:
pRadiobox(Radiobox&);
/* internal */
GtkWidget *radiobox;
GtkWidget* gtk_handle();
GtkWidget *radiobox;
bool locked;
};

View File

@@ -65,6 +65,7 @@ void pWindow::create(uint style, uint width, uint height, const char *text) {
//without affecting the statusbar color
statuscontainer = gtk_event_box_new();
statusbar = gtk_statusbar_new();
set_default_font(statusbar);
gtk_container_add(GTK_CONTAINER(statuscontainer), statusbar);
gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), false);
gtk_box_pack_start(GTK_BOX(menucontainer), statuscontainer, false, false, 0);

View File

@@ -1,6 +1,6 @@
/*
hiro
version: 0.003 (2008-04-06)
version: 0.005 (2008-05-25)
author: byuu
license: public domain
*/
@@ -11,6 +11,7 @@
#include <nall/array.hpp>
#include <nall/function.hpp>
#include <nall/input.hpp>
#include <nall/new.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>

237
src/lib/hiro/test/test.cpp Normal file
View File

@@ -0,0 +1,237 @@
#include "../hiro.h"
using namespace libhiro;
#include <nall/algorithm.hpp>
using nall::min;
using nall::max;
bool kill_ = false;
uint32_t windowicon[16 * 16] = {
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
};
class SubWindow : public Window {
public:
Button button;
uintptr_t tick(Event) {
hide();
}
void setup() {
create(0, 595, 80);
button.create(0, 595, 80, "SubWindow (click to hide)");
button.on_tick = bind(&SubWindow::tick, this);
attach(button, 0, 0);
}
} subwindow;
class MainWindow : public Window {
public:
MenuGroup menu_file;
MenuGroup menu_file_disk;
MenuItem menu_file_disk_load;
MenuItem menu_file_disk_save;
MenuSeparator menu_file_separator;
MenuItem menu_file_exit;
MenuGroup menu_help;
MenuCheckItem menu_help_check1, menu_help_check2;
MenuSeparator menu_help_separator1;
MenuRadioItem menu_help_radio1, menu_help_radio2, menu_help_radio3;
MenuSeparator menu_help_separator2;
MenuItem menu_help_about;
Label label;
Editbox editbox, editbox_multi;
Button button_ok;
Button button_exit;
Checkbox check1, check2;
Radiobox radio1, radio2;
Progressbar progress;
Combobox combobox;
Listbox listbox;
Slider hslider, vslider;
Frame frame;
Canvas canvas;
uintptr_t change(Event e) {
printf("change(%d)\n", (uint)e.param);
}
uintptr_t activate(Event e) {
printf("activate(%d)\n", (uint)e.param);
}
uintptr_t tick(Event e) {
printf("tick(%d)\n", e.param);
if(e.widget == &button_ok) {
char t[4096];
editbox.get_text(t, 4096);
printf("'%s'\n", t);
}
if(e.widget == &menu_file_disk_load) {
char t[4096] = "";
hiro().file_open(0, t, "", "Source files\t*.cpp,*.h\nAll Files\t*.*");
printf("'%s'\n", t);
}
if(e.widget == &menu_file_disk_save) {
char t[4096] = "";
hiro().file_save(0, t, "", "Source files\t*.cpp,*.h\nAll Files\t*.*");
printf("'%s'\n", t);
}
}
uintptr_t keydown(Event e) {
static bool fs = false;
if(e.param == nall::keyboard::f11) {
fs = !fs;
fs ? fullscreen() : unfullscreen();
printf("%d -> %4d, %4d\n", fs, get_width(), get_height());
} else if(e.param == nall::keyboard::escape) {
menu.show(!menu.visible());
}
}
uintptr_t close(Event) {
printf("close()\n");
return kill_ = true;
}
void setup() {
create(Window::AutoCenter, 605, 320, "hiro test application");
//set_opacity(224);
//set_background_color(0, 0, 0);
set_icon(16, 16, windowicon);
attach(menu_file.create("File"));
menu_file.attach(menu_file_disk.create("Disk"));
menu_file_disk.attach(menu_file_disk_load.create("Load ..."));
menu_file_disk.attach(menu_file_disk_save.create("Save ..."));
menu_file.attach(menu_file_separator.create());
menu_file.attach(menu_file_exit.create("Exit"));
attach(menu_help.create("Help"));
menu_help.attach(menu_help_check1.create("Check 1"));
menu_help.attach(menu_help_check2.create("Check 2"));
menu_help.attach(menu_help_separator1.create());
{ MenuRadioItemGroup group;
group.add(&menu_help_radio1);
group.add(&menu_help_radio2);
group.add(&menu_help_radio3);
menu_help.attach(menu_help_radio1.create(group, "Radio 1"));
menu_help.attach(menu_help_radio2.create(group, "Radio 2"));
menu_help.attach(menu_help_radio3.create(group, "Radio 3"));
} menu_help.attach(menu_help_separator2.create());
menu_help.attach(menu_help_about.create("About ..."));
menu_help_about.disable();
label.create(0, 200, 35, "hiro test application\n~ byuu");
editbox.create(0, 200, 25);
button_ok.create(0, 100, 30, "Ok");
button_exit.create(0, 100, 30, "Exit");
editbox_multi.create(Editbox::Multiline | Editbox::VerticalScrollAlways, 200, 95);
check1.create(0, 100, 20, "Check 1");
check2.create(0, 100, 20, "Check 2");
{ RadioboxGroup group;
group.add(&radio1);
group.add(&radio2);
radio1.create(group, 0, 100, 20, "Radio 1");
radio2.create(group, 0, 100, 20, "Radio 2");
} progress.create(0, 200, 30);
progress.set_progress(50);
combobox.create(0, 200, 30);
combobox.add_item("Option 1");
combobox.add_item("Option 2");
combobox.add_item("Option 3");
listbox.create(Listbox::Header | Listbox::VerticalScrollAlways, 200, 100, "Name\tValue");
listbox.add_item("a\ttrue");
listbox.add_item("b\tfalse");
hslider.create(Slider::Horizontal, 425, 25, 10);
vslider.create(Slider::Vertical, 25, 200, 10);
frame.create(0, 155, 225, "Canvas:");
canvas.create(0, 135, 195);
for(uint y = 0; y < 195; y++) {
uint32_t *p = canvas.buffer() + y * 135;
for(uint x = 0; x < 135; x++) {
double dx = 128.0 / 135.0 * double(x);
double dy = 128.0 / 195.0 * double(y);
uint32_t c = uint32_t(dx) + uint32_t(dy);
*p++ = (max(0U, min(c, 255U)) ^ 0xff) << 16;
}
}
status.show();
status.set_text("Statusbar");
on_close = bind(&MainWindow::close, this);
on_keydown = bind(&MainWindow::keydown, this);
menu_file_disk_load.on_tick =
menu_file_disk_save.on_tick = bind(&MainWindow::tick, this);
menu_file_exit.on_tick = on_close;
menu_help_check1.on_tick = menu_help_check2.on_tick =
menu_help_radio1.on_tick = menu_help_radio2.on_tick =
menu_help_radio3.on_tick = bind(&MainWindow::tick, this);
menu_help_about.on_tick = bind(&MainWindow::tick, this);
button_ok.on_tick = bind(&MainWindow::tick, this);
button_exit.on_tick = bind(&MainWindow::close, this);
check1.on_tick = check2.on_tick =
radio1.on_tick = radio2.on_tick = bind(&MainWindow::tick, this);
combobox.on_change = bind(&MainWindow::change, this);
listbox.on_change = bind(&MainWindow::change, this);
listbox.on_activate = bind(&MainWindow::activate, this);
hslider.on_change = bind(&MainWindow::change, this);
vslider.on_change = bind(&MainWindow::change, this);
attach(label, 5, 5);
attach(editbox, 5, 40);
attach(button_ok, 5, 70);
attach(button_exit, 105, 70);
attach(editbox_multi, 210, 5);
attach(check1, 5, 105);
attach(check2, 105, 105);
attach(radio1, 5, 125);
attach(radio2, 105, 125);
attach(progress, 5, 145);
attach(combobox, 5, 175);
attach(listbox, 210, 105);
attach(hslider, 5, 205);
attach(vslider, 415, 5);
attach(frame, 445, 5);
attach(canvas, 455, 25);
attach(subwindow, 5, 235);
}
} window;
int main() {
hiro().init();
hiro().disable_screensaver();
subwindow.setup();
window.setup();
window.show();
window.check1.check();
while(kill_ == false) hiro().run();
hiro().term();
return 0;
}

View File

@@ -1,5 +1,5 @@
void pButton::create(uint style, uint width, uint height, const char *text) {
hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_TABSTOP | WS_VISIBLE,
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_TABSTOP | WS_VISIBLE,
0, 0, width, height,
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
@@ -7,7 +7,7 @@ void pButton::create(uint style, uint width, uint height, const char *text) {
}
void pButton::set_text(const char *text) {
SetWindowText(hwnd, text ? text : "");
SetWindowText(hwnd, utf16(text));
}
pButton::pButton(Button &self_) : pFormControl(self_), self(self_) {

View File

@@ -1,5 +1,5 @@
void pCanvas::create(uint style, uint width, uint height) {
hwnd = CreateWindow("hiro_window", "", WS_CHILD,
hwnd = CreateWindow(L"hiro_window", L"", WS_CHILD,
0, 0, width, height,
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
@@ -8,6 +8,11 @@ void pCanvas::create(uint style, uint width, uint height) {
}
void pCanvas::redraw() {
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
SetDIBitsToDevice(ps.hdc, 0, 0, iwidth, iheight, 0, 0, 0, iheight, (void*)ibuffer, &bmi, DIB_RGB_COLORS);
EndPaint(hwnd, &ps);
InvalidateRect(hwnd, 0, FALSE);
}
uint32_t* pCanvas::buffer() {
@@ -30,13 +35,6 @@ pCanvas::~pCanvas() {
/* internal */
void pCanvas::blit() {
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
SetDIBitsToDevice(ps.hdc, 0, 0, iwidth, iheight, 0, 0, 0, iheight, (void*)ibuffer, &bmi, DIB_RGB_COLORS);
EndPaint(hwnd, &ps);
}
void pCanvas::resize(uint width, uint height) {
if(ibuffer) free(ibuffer);

View File

@@ -12,6 +12,5 @@ public:
BITMAPINFO bmi;
uint32_t *ibuffer;
uint ipitch, iwidth, iheight;
void blit();
void resize(uint width, uint height);
};

View File

@@ -1,20 +1,16 @@
void pCheckbox::create(uint style, uint width, uint height, const char *text) {
hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_CHECKBOX,
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_CHECKBOX,
0, 0, width, height,
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
}
void pCheckbox::set_text(const char *text) {
SetWindowText(hwnd, text ? text : "");
SetWindowText(hwnd, utf16(text));
}
void pCheckbox::check(bool state) {
bool prev = checked();
SendMessage(hwnd, BM_SETCHECK, (WPARAM)(state ? TRUE : FALSE), 0);
if(prev != state) {
if(self.on_tick) self.on_tick(Event(Event::Tick, state, &self));
}
}
void pCheckbox::uncheck() {

View File

@@ -1,5 +1,5 @@
void pCombobox::create(uint style, uint width, uint height, const char *text) {
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "COMBOBOX", "",
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"COMBOBOX", L"",
WS_CHILD | WS_TABSTOP | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
0, 0, width, 200,
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
@@ -17,7 +17,7 @@ void pCombobox::create(uint style, uint width, uint height, const char *text) {
}
void pCombobox::add_item(const char *text) {
SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)text);
SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)(wchar_t*)utf16(text));
if(SendMessage(hwnd, CB_GETCOUNT, 0, 0) == 1) set_selection(0);
}

View File

@@ -8,7 +8,7 @@ void pEditbox::create(uint style, uint width, uint height, const char *text) {
(style & Editbox::HorizontalScrollNever) ? 0 :
ES_AUTOHSCROLL;
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "",
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
WS_CHILD | WS_VISIBLE | vscroll | hscroll |
(multiline == true ? ES_MULTILINE | ES_WANTRETURN : WS_TABSTOP) |
(readonly == true ? ES_READONLY : 0),
@@ -22,14 +22,15 @@ void pEditbox::set_text(const char *text) {
string temp = text ? text : "";
replace(temp, "\r", "");
replace(temp, "\n", "\r\n");
SetWindowText(hwnd, temp);
SetWindowText(hwnd, utf16(temp));
}
uint pEditbox::get_text(char *text, uint length) {
GetWindowText(hwnd, text, length);
string temp = text;
wchar_t buffer[length * 2 + 1];
GetWindowText(hwnd, buffer, length * 2);
string temp = (const char*)utf8(buffer);
replace(temp, "\r", "");
strcpy(text, temp);
strlcpy(text, temp, length);
return strlen(text);
}

View File

@@ -1,12 +1,12 @@
void pFrame::create(uint style, uint width, uint height, const char *text) {
hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
0, 0, width, height,
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
}
void pFrame::set_text(const char *text) {
SetWindowText(hwnd, text ? text : "");
SetWindowText(hwnd, utf16(text));
}
pFrame::pFrame(Frame &self_) : pFormControl(self_), self(self_) {

View File

@@ -8,6 +8,7 @@ namespace libhiro {
LRESULT CALLBACK phiro_wndproc(HWND, UINT, WPARAM, LPARAM);
#include "utf.cpp"
#include "keymap.cpp"
#include "widget.cpp"
#include "window.cpp"
@@ -43,14 +44,14 @@ void pHiro::init() {
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = phiro_wndproc;
wc.lpszClassName = "hiro_window";
wc.lpszClassName = L"hiro_window";
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
InitCommonControls();
default_hwnd = CreateWindow("hiro_window", "", WS_POPUP, 0, 0, 640, 480, 0, 0, GetModuleHandle(0), 0);
default_font = create_font("Tahoma", 9);
default_hwnd = CreateWindow(L"hiro_window", L"", WS_POPUP, 0, 0, 640, 480, 0, 0, GetModuleHandle(0), 0);
default_font = create_font("Tahoma", 8);
black_brush = CreateSolidBrush(RGB(0, 0, 0));
}
@@ -76,12 +77,13 @@ bool pHiro::pending() {
}
bool pHiro::folder_select(Window *focus, char *filename, const char *path) {
wchar_t wfilename[_MAX_PATH] = L"";
strcpy(filename, "");
BROWSEINFO bi;
bi.hwndOwner = focus ? focus->p.hwnd : 0;
bi.pidlRoot = NULL;
bi.pszDisplayName = filename;
bi.lpszTitle = "Select Folder";
bi.pszDisplayName = wfilename;
bi.lpszTitle = L"";
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS;
bi.lpfn = NULL;
bi.lParam = 0;
@@ -89,7 +91,7 @@ bool pHiro::folder_select(Window *focus, char *filename, const char *path) {
bool result = false;
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
if(pidl) {
if(SHGetPathFromIDList(pidl, filename)) {
if(SHGetPathFromIDList(pidl, wfilename)) {
result = true;
IMalloc *imalloc = 0;
if(SUCCEEDED(SHGetMalloc(&imalloc))) {
@@ -98,6 +100,7 @@ bool pHiro::folder_select(Window *focus, char *filename, const char *path) {
}
}
}
strcpy(filename, utf8(wfilename));
return result;
}
@@ -108,23 +111,28 @@ bool pHiro::file_open(Window *focus, char *filename, const char *path, const cha
lstring type, part;
strcpy(f, "");
split(type, "|", filter);
split(type, "\n", filter);
for(int i = 0; i < count(type); i++) {
split(part, ";", type[i]);
if(count(part) != 2)continue;
split(part, "\t", type[i]);
if(count(part) != 2) continue;
strcat(f, part[0]);
strcat(f, " (");
strcat(f, part[1]);
strcat(f, ")|");
strcat(f, ")\t");
replace(part[1], ",", ";");
strcat(f, part[1]);
strcat(f, "|");
strcat(f, "\t");
}
char *pf = f();
for(int i = strlen(pf) - 1; i >= 0; i--) {
if(pf[i] == '|') pf[i] = '\0';
utf16 wfilter(f);
utf16 wdir(dir);
wchar_t wfilename[_MAX_PATH] = L"";
wchar_t *p = wfilter;
while(*p != L'\0') {
if(*p == L'\t') *p = L'\0';
p++;
}
OPENFILENAME ofn;
@@ -132,14 +140,16 @@ bool pHiro::file_open(Window *focus, char *filename, const char *path, const cha
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = focus ? focus->p.hwnd : 0;
ofn.lpstrFilter = pf;
ofn.lpstrInitialDir = dir;
ofn.lpstrFile = filename;
ofn.lpstrFilter = wfilter;
ofn.lpstrInitialDir = wdir;
ofn.lpstrFile = wfilename;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
ofn.lpstrDefExt = "";
ofn.lpstrDefExt = L"";
return GetOpenFileName(&ofn);
bool result = GetOpenFileName(&ofn);
strcpy(filename, utf8(wfilename));
return result;
}
bool pHiro::file_save(Window *focus, char *filename, const char *path, const char *filter) {
@@ -149,23 +159,28 @@ bool pHiro::file_save(Window *focus, char *filename, const char *path, const cha
lstring type, part;
strcpy(f, "");
split(type, "|", filter);
split(type, "\n", filter);
for(int i = 0; i < count(type); i++) {
split(part, ";", type[i]);
if(count(part) != 2)continue;
split(part, "\t", type[i]);
if(count(part) != 2) continue;
strcat(f, part[0]);
strcat(f, " (");
strcat(f, part[1]);
strcat(f, ")|");
strcat(f, ")\t");
replace(part[1], ",", ";");
strcat(f, part[1]);
strcat(f, "|");
strcat(f, "\t");
}
char *pf = f();
for(int i = strlen(pf) - 1; i >= 0; i--) {
if(pf[i] == '|') pf[i] = '\0';
utf16 wfilter(f);
utf16 wdir(dir);
wchar_t wfilename[_MAX_PATH] = L"";
wchar_t *p = wfilter;
while(*p != L'\0') {
if(*p == L'\t') *p = L'\0';
p++;
}
OPENFILENAME ofn;
@@ -173,14 +188,16 @@ bool pHiro::file_save(Window *focus, char *filename, const char *path, const cha
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = focus ? focus->p.hwnd : 0;
ofn.lpstrFilter = pf;
ofn.lpstrInitialDir = dir;
ofn.lpstrFile = filename;
ofn.lpstrFilter = wfilter;
ofn.lpstrInitialDir = wdir;
ofn.lpstrFile = wfilename;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
ofn.lpstrDefExt = "";
ofn.lpstrDefExt = L"";
return GetSaveFileName(&ofn);
bool result = GetSaveFileName(&ofn);
strcpy(filename, utf8(wfilename));
return result;
}
uint pHiro::screen_width() {
@@ -214,11 +231,11 @@ pHiro& phiro() {
/* internal */
HFONT pHiro::create_font(const char *name, uint size) {
HDC hdc = GetDC(0);
HFONT font = CreateFont(-MulDiv(size, GetDeviceCaps(hdc, LOGPIXELSY), 72),
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, name);
ReleaseDC(0, hdc);
return font;
return CreateFont(
-(size * 96.0 / 72.0 + 0.5), //96 = DPI
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
utf16(name)
);
}
Widget* pHiro::get_widget(uint instance) {
@@ -256,38 +273,38 @@ LRESULT pHiro::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
case WM_CLOSE: {
if(!p || p->self.type != Widget::WindowType) break;
Window &w = ((pWindow*)p)->self;
Window &w = ((pWindow*)p)->self;
if(w.on_close) return (bool)w.on_close(Event(Event::Close, 0, &w));
return TRUE; //true = destroy window
} break;
case WM_ENTERMENULOOP: {
if(!p || p->self.type != Widget::WindowType) break;
Window &w = ((pWindow*)p)->self;
Window &w = ((pWindow*)p)->self;
if(w.on_block) w.on_block(Event(Event::Block, 0, &w));
} break;
case WM_KEYDOWN: {
if(!p || p->self.type != Widget::WindowType) break;
Window &w = ((pWindow*)p)->self;
Window &w = ((pWindow*)p)->self;
if(w.on_keydown) w.on_keydown(Event(Event::KeyDown, translate_key(wparam), &w));
} break;
case WM_KEYUP: {
if(!p || p->self.type != Widget::WindowType) break;
Window &w = ((pWindow*)p)->self;
Window &w = ((pWindow*)p)->self;
if(w.on_keyup) w.on_keyup(Event(Event::KeyUp, translate_key(wparam), &w));
} break;
case WM_ERASEBKGND: {
if(!p) break;
HBRUSH brush = 0;
HBRUSH brush = 0;
if(p->self.type == Widget::WindowType) brush = ((pWindow*)p)->background;
if(p->self.type == Widget::CanvasType) brush = phiro().black_brush;
if(!brush) break;
RECT rc;
RECT rc;
GetClientRect(hwnd, &rc);
PAINTSTRUCT ps;
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
FillRect(ps.hdc, &rc, brush);
EndPaint(hwnd, &ps);
@@ -295,40 +312,46 @@ LRESULT pHiro::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
} break;
case WM_PAINT: {
if(p && p->self.type == Widget::CanvasType) ((pCanvas*)p)->blit();
if(p && p->self.type == Widget::CanvasType) ((pCanvas*)p)->redraw();
} break;
case WM_COMMAND: {
Widget *widget = get_widget(LOWORD(wparam));
Widget *widget = get_widget(LOWORD(wparam));
if(!widget) break;
switch(widget->type) {
case Widget::MenuItemType: {
MenuItem &w = (MenuItem&)*widget;
MenuItem &w = (MenuItem&)*widget;
if(w.on_tick) w.on_tick(Event(Event::Tick, 0, &w));
} break;
case Widget::MenuCheckItemType: {
MenuCheckItem &w = (MenuCheckItem&)*widget;
MenuCheckItem &w = (MenuCheckItem&)*widget;
w.check(!w.checked()); //invert check state
if(w.on_tick) w.on_tick(Event(Event::Tick, w.checked(), &w));
} break;
case Widget::MenuRadioItemType: {
MenuRadioItem &w = (MenuRadioItem&)*widget;
MenuRadioItem &w = (MenuRadioItem&)*widget;
bool checked = w.checked();
w.check();
if(!checked && w.on_tick) w.on_tick(Event(Event::Tick, w.checked(), &w));
} break;
case Widget::ButtonType: {
Button &w = (Button&)*widget;
Button &w = (Button&)*widget;
if(w.on_tick) w.on_tick(Event(Event::Tick, 0, &w));
} break;
case Widget::CheckboxType: {
Checkbox &w = (Checkbox&)*widget;
Checkbox &w = (Checkbox&)*widget;
w.check(!w.checked()); //invert check state
if(w.on_tick) w.on_tick(Event(Event::Tick, w.checked(), &w));
} break;
case Widget::RadioboxType: {
Radiobox &w = (Radiobox&)*widget;
Radiobox &w = (Radiobox&)*widget;
bool checked = w.checked();
w.check();
if(!checked && w.on_tick) w.on_tick(Event(Event::Tick, w.checked(), &w));
} break;
case Widget::ComboboxType: {
Combobox &combobox = (Combobox&)*widget;
Combobox &combobox = (Combobox&)*widget;
if(HIWORD(wparam) == CBN_SELCHANGE) {
if(combobox.p.combobox_selection == combobox.get_selection()) break;
if(combobox.on_change) combobox.on_change(Event(Event::Change, combobox.p.combobox_selection = combobox.get_selection(), &combobox));
@@ -339,12 +362,12 @@ LRESULT pHiro::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
case WM_HSCROLL:
case WM_VSCROLL: {
Widget *widget = get_widget(GetDlgCtrlID((HWND)lparam));
Widget *widget = get_widget(GetDlgCtrlID((HWND)lparam));
if(!widget) break;
switch(widget->type) {
case Widget::SliderType: {
Slider &slider = (Slider&)*widget;
Slider &slider = (Slider&)*widget;
if(slider.p.slider_position == slider.get_position()) break;
if(slider.on_change) slider.on_change(Event(Event::Change, slider.p.slider_position = slider.get_position(), &slider));
} break;
@@ -352,12 +375,12 @@ LRESULT pHiro::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
} break;
case WM_NOTIFY: {
Widget *widget = get_widget(LOWORD(wparam));
Widget *widget = get_widget(LOWORD(wparam));
if(!widget) break;
switch(widget->type) {
case Widget::ListboxType: {
Listbox &listbox = (Listbox&)*widget;
Listbox &listbox = (Listbox&)*widget;
if(((LPNMHDR)lparam)->code == LVN_ITEMCHANGED
&& ((LPNMLISTVIEW)lparam)->uChanged & LVIF_STATE
&& ListView_GetItemState(listbox.p.hwnd, ((LPNMLISTVIEW)lparam)->iItem, LVIS_FOCUSED)

View File

@@ -11,6 +11,7 @@
#define _WIN32_IE 0x0600
#define NOMINMAX
#define UNICODE
#include <windows.h>
#include <commctrl.h>
#include <shlobj.h>

View File

@@ -30,6 +30,13 @@ uint16_t pHiro::translate_key(uint key) {
case '8': return keyboard::num_8;
case '9': return keyboard::num_9;
case VK_INSERT: return keyboard::insert;
case VK_DELETE: return keyboard::delete_;
case VK_HOME: return keyboard::home;
case VK_END: return keyboard::end;
case VK_PRIOR: return keyboard::page_up;
case VK_NEXT: return keyboard::page_down;
case 'A': return keyboard::a;
case 'B': return keyboard::b;
case 'C': return keyboard::c;

View File

@@ -1,12 +1,12 @@
void pLabel::create(uint style, uint width, uint height, const char *text) {
hwnd = CreateWindow("STATIC", text ? text : "", WS_CHILD | WS_VISIBLE,
hwnd = CreateWindow(L"STATIC", utf16(text), WS_CHILD | WS_VISIBLE,
0, 0, width, height,
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
}
void pLabel::set_text(const char *text) {
SetWindowText(hwnd, text ? text : "");
SetWindowText(hwnd, utf16(text));
}
pLabel::pLabel(Label &self_) : pFormControl(self_), self(self_) {

View File

@@ -1,12 +1,12 @@
void pListbox::create(uint style, uint width, uint height, const char *columns, const char *text) {
bool header = style & Listbox::Header;
uint hscroll = (style & Listbox::HorizontalScrollAlways) ? WS_HSCROLL :
(style & Listbox::HorizontalScrollNever) ? 0 :
0;
uint vscroll = (style & Listbox::VerticalScrollAlways) ? WS_VSCROLL :
(style & Listbox::VerticalScrollNever) ? 0 :
0;
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "",
bool header = style & Listbox::Header;
unsigned hscroll = (style & Listbox::HorizontalScrollAlways) ? WS_HSCROLL :
(style & Listbox::HorizontalScrollNever) ? 0 :
0;
unsigned vscroll = (style & Listbox::VerticalScrollAlways) ? WS_VSCROLL :
(style & Listbox::VerticalScrollNever) ? 0 :
0;
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, L"",
WS_CHILD | WS_TABSTOP | WS_VISIBLE |
LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | vscroll | hscroll |
(header ? 0 : LVS_NOCOLUMNHEADER),
@@ -15,27 +15,28 @@ uint vscroll = (style & Listbox::VerticalScrollAlways) ? WS_VSCROLL :
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT);
lstring list;
lstring list;
split(list, "\t", columns ? columns : "");
column_count = count(list);
for(uint i = 0; i < count(list); i++) {
LVCOLUMN column;
for(unsigned i = 0; i < count(list); i++) {
LVCOLUMN column;
column.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM;
column.fmt = LVCFMT_LEFT;
column.iSubItem = count(list);
column.pszText = (LPSTR)list[i]();
utf16 ulist(list[i]);
column.pszText = ulist;
ListView_InsertColumn(hwnd, i, &column);
}
if(text && *text) {
split(list, "\n", text);
for(uint i = 0; i < count(list); i++) add_item(list[i]);
for(unsigned i = 0; i < count(list); i++) add_item(list[i]);
}
autosize_columns();
}
void pListbox::autosize_columns() {
for(uint i = 0; i < column_count; i++) {
for(unsigned i = 0; i < column_count; i++) {
ListView_SetColumnWidth(hwnd, i, LVSCW_AUTOSIZE_USEHEADER);
}
}
@@ -45,40 +46,43 @@ void pListbox::set_column_width(uint column, uint width) {
}
void pListbox::add_item(const char *text) {
lstring list;
lstring list;
split(list, "\t", text ? text : "");
LVITEM item;
uint pos = ListView_GetItemCount(hwnd);
LVITEM item;
unsigned pos = ListView_GetItemCount(hwnd);
item.mask = LVIF_TEXT;
item.iItem = pos;
item.iSubItem = 0;
item.pszText = (LPSTR)list[0]();
utf16 wtext(list[0]);
item.pszText = wtext;
ListView_InsertItem(hwnd, &item);
for(uint i = 1; i < count(list); i++) {
ListView_SetItemText(hwnd, pos, i, (LPSTR)list[i]());
for(unsigned i = 1; i < count(list); i++) {
utf16 wtext(list[i]);
ListView_SetItemText(hwnd, pos, i, wtext);
}
}
void pListbox::set_item(uint index, const char *text) {
lstring list;
lstring list;
split(list, "\t", text ? text : "");
for(uint i = 0; i < count(list); i++) {
ListView_SetItemText(hwnd, index, i, list[i]());
for(unsigned i = 0; i < count(list); i++) {
utf16 wtext(list[i]);
ListView_SetItemText(hwnd, index, i, wtext);
}
}
int pListbox::get_selection() {
uint count = ListView_GetItemCount(hwnd);
for(uint i = 0; i < count; i++) {
unsigned count = ListView_GetItemCount(hwnd);
for(unsigned i = 0; i < count; i++) {
if(ListView_GetItemState(hwnd, i, LVIS_SELECTED)) return i;
}
return -1;
}
void pListbox::set_selection(int index) {
uint count = ListView_GetItemCount(hwnd);
for(uint i = 0; i < count; i++) {
unsigned count = ListView_GetItemCount(hwnd);
for(unsigned i = 0; i < count; i++) {
ListView_SetItemState(hwnd, i, LVIS_FOCUSED, (i == index) ? LVIS_FOCUSED : 0);
ListView_SetItemState(hwnd, i, LVIS_SELECTED, (i == index) ? LVIS_SELECTED : 0);
}

View File

@@ -3,11 +3,7 @@ void pMenuCheckItem::create(const char *text_) {
}
void pMenuCheckItem::check(bool state) {
bool prev = checked();
CheckMenuItem(parent, instance, state ? MF_CHECKED : MF_UNCHECKED);
if(prev != state) {
if(self.on_tick) self.on_tick(Event(Event::Tick, state, &self));
}
}
void pMenuCheckItem::uncheck() {
@@ -15,7 +11,7 @@ void pMenuCheckItem::uncheck() {
}
bool pMenuCheckItem::checked() {
MENUITEMINFO info;
MENUITEMINFO info;
memset(&info, 0, sizeof info);
info.cbSize = sizeof info;
info.fMask = MIIM_STATE;

View File

@@ -6,20 +6,20 @@ void pMenuGroup::create(const char *text_) {
void pMenuGroup::attach(MenuControl &menucontrol) {
switch(menucontrol.type) {
case Widget::MenuGroupType: {
AppendMenu(group, MF_STRING | MF_POPUP, (uint)((MenuGroup&)menucontrol).p.group, menucontrol.p.text);
AppendMenu(group, MF_STRING | MF_POPUP, (uint)((MenuGroup&)menucontrol).p.group, utf16(menucontrol.p.text));
} break;
case Widget::MenuItemType:
case Widget::MenuCheckItemType:
case Widget::MenuRadioItemType: {
AppendMenu(group, MF_STRING, menucontrol.p.instance, menucontrol.p.text);
AppendMenu(group, MF_STRING, menucontrol.p.instance, utf16(menucontrol.p.text));
if(menucontrol.type == Widget::MenuRadioItemType && ((MenuRadioItem&)menucontrol).p.create_checked) {
CheckMenuItem(group, menucontrol.p.instance, MF_CHECKED);
}
} break;
case Widget::MenuSeparatorType: {
AppendMenu(group, MF_SEPARATOR, menucontrol.p.instance, "");
AppendMenu(group, MF_SEPARATOR, menucontrol.p.instance, L"");
} break;
}

View File

@@ -5,15 +5,13 @@ void pMenuRadioItem::create(MenuRadioItemGroup &group_, const char *text_) {
}
void pMenuRadioItem::check() {
bool prev = checked();
for(uint i = 0; i < group.size(); i++) {
CheckMenuItem(parent, group[i]->p.instance, (group[i] == &self) ? MF_CHECKED : MF_UNCHECKED);
}
if(prev == false && self.on_tick) self.on_tick(Event(Event::Tick, 0, &self));
}
bool pMenuRadioItem::checked() {
MENUITEMINFO info;
MENUITEMINFO info;
memset(&info, 0, sizeof info);
info.cbSize = sizeof info;
info.fMask = MIIM_STATE;

View File

@@ -1,5 +1,5 @@
void pProgressbar::create(uint style, uint width, uint height) {
hwnd = CreateWindow(PROGRESS_CLASS, "", WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
hwnd = CreateWindow(PROGRESS_CLASS, L"", WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
0, 0, width, height,
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));

View File

@@ -1,21 +1,19 @@
void pRadiobox::create(RadioboxGroup &group_, uint style, uint width, uint height, const char *text) {
group = group_;
hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_RADIOBUTTON,
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_RADIOBUTTON,
0, 0, width, height, phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
if(group[0] == &self) check();
}
void pRadiobox::set_text(const char *text) {
SetWindowText(hwnd, text);
SetWindowText(hwnd, utf16(text));
}
void pRadiobox::check() {
bool prev = checked();
for(uint i = 0; i < group.size(); i++) {
SendMessage(group[i]->p.hwnd, BM_SETCHECK, (WPARAM)(group[i] == &self), 0);
}
if(prev == false && self.on_tick) self.on_tick(Event(Event::Tick, 0, &self));
}
bool pRadiobox::checked() {

View File

@@ -1,7 +1,7 @@
void pSlider::create(uint style, uint width, uint height, uint length) {
if(length < 1) length = 1;
hwnd = CreateWindow(TRACKBAR_CLASS, "",
hwnd = CreateWindow(TRACKBAR_CLASS, L"",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH |
(style & Slider::Vertical ? TBS_VERT : TBS_HORZ),
0, 0, width, height,

55
src/lib/hiro/win/utf.cpp Normal file
View File

@@ -0,0 +1,55 @@
/*****
* UTF-8 to UTF-16
*****/
class utf16 {
public:
operator wchar_t*() {
return buffer;
}
operator const wchar_t*() const {
return buffer;
}
utf16(const char *s = "") {
if(!s) s = "";
unsigned length = MultiByteToWideChar(CP_UTF8, 0, s, -1, 0, 0);
buffer = new(zeromemory) wchar_t[length + 1];
MultiByteToWideChar(CP_UTF8, 0, s, -1, buffer, length);
}
~utf16() {
delete[] buffer;
}
private:
wchar_t *buffer;
};
/*****
* UTF-16 to UTF-8
*****/
class utf8 {
public:
operator char*() {
return buffer;
}
operator const char*() const {
return buffer;
}
utf8(const wchar_t *s = L"") {
if(!s) s = L"";
unsigned length = WideCharToMultiByte(CP_UTF8, 0, s, -1, 0, 0, (const char*)0, (BOOL*)0);
buffer = new(zeromemory) char[length + 1];
WideCharToMultiByte(CP_UTF8, 0, s, -1, buffer, length, (const char*)0, (BOOL*)0);
}
~utf8() {
delete[] buffer;
}
private:
char *buffer;
};

View File

@@ -4,16 +4,16 @@ void pWindow::create(uint style, uint width_, uint height_, const char *text) {
RECT rc;
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
hwnd = CreateWindowEx(0, "hiro_window", text ? text : "",
hwnd = CreateWindowEx(0, L"hiro_window", utf16(text),
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
rc.left, rc.top, width_, height_,
0, 0, GetModuleHandle(0), 0);
hwndr = CreateWindowEx(0, "hiro_window", text ? text : "",
hwndr = CreateWindowEx(0, L"hiro_window", utf16(text),
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
rc.left, rc.top, width_, height_,
0, 0, GetModuleHandle(0), 0);
hmenu = CreateMenu();
hstatus = CreateWindowEx(0, STATUSCLASSNAME, "",
hstatus = CreateWindowEx(0, STATUSCLASSNAME, L"",
WS_CHILD, 0, 0, 0, 0, hwnd, 0, GetModuleHandle(0), 0);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
@@ -194,7 +194,7 @@ void pWindow::set_icon(unsigned width, unsigned height, const uint32_t *data) {
}
void pWindow::set_text(const char *text) {
SetWindowText(hwnd, text);
SetWindowText(hwnd, utf16(text));
}
void pWindow::attach(Window &window, uint x, uint y) {
@@ -214,7 +214,7 @@ void pWindow::attach(Window &window, uint x, uint y) {
}
void pWindow::attach(MenuGroup &menugroup) {
AppendMenu(hmenu, MF_STRING | MF_POPUP, (uint)menugroup.p.group, menugroup.p.text);
AppendMenu(hmenu, MF_STRING | MF_POPUP, (uint)menugroup.p.group, utf16(menugroup.p.text));
if(menu_visible() == false) menu_show();
}
@@ -317,7 +317,7 @@ bool pWindow::menu_visible() {
}
void pWindow::status_set_text(const char *text) {
SendMessage(hstatus, SB_SETTEXT, 0, (LPARAM)text);
SendMessage(hstatus, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16(text));
}
void pWindow::status_show(bool state) {

View File

@@ -71,15 +71,15 @@ void HQ2xFilter::render(
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
#define W1 input[-1 - pitch]
#define W2 input[ 0 - pitch]
#define W3 input[+1 - pitch]
#define W1 input[-1 - (int)pitch]
#define W2 input[ 0 - (int)pitch]
#define W3 input[+1 - (int)pitch]
#define W4 input[-1]
#define W5 input[ 0]
#define W6 input[+1]
#define W7 input[-1 + pitch]
#define W8 input[ 0 + pitch]
#define W9 input[+1 + pitch]
#define W7 input[-1 + (int)pitch]
#define W8 input[ 0 + (int)pitch]
#define W9 input[+1 + (int)pitch]
input += pitch;
memset(out0, 0, 2048); out0 += outpitch << 1;

View File

@@ -0,0 +1,66 @@
#ifndef NALL_DICTIONARY_HPP
#define NALL_DICTIONARY_HPP
#include <nall/array.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
namespace nall {
class dictionary : noncopyable {
public:
const char* operator[](const char *input) const {
for(unsigned i = 0; i < index_input.size(); i++) {
if(!strcmp(input, index_input[i])) return index_output[i];
}
return input; //no match, return input rather than null string
}
bool import(const char *filename) {
string data;
if(fread(data, filename) == false) return false;
replace(data, "\r", "");
lstring line;
split(line, "\n", data);
for(unsigned i = 0; i < count(line); i++) {
lstring part;
//format: "Input" = "Output"
qsplit(part, "=", line[i]);
if(count(part) != 2) continue;
//remove whitespace
trim(part[0]);
trim(part[1]);
//remove quotes
trim_once(part[0], "\"");
trim_once(part[1], "\"");
unsigned i = index_input.size();
index_input[i] = strdup(part[0]);
index_output[i] = strdup(part[1]);
}
}
void reset() {
for(unsigned i = 0; i < index_input.size(); i++) {
free(index_input[i]);
free(index_output[i]);
}
index_input.reset();
index_output.reset();
}
~dictionary() {
reset();
}
private:
array<char*> index_input;
array<char*> index_output;
};
} //namespace nall
#endif //ifndef NALL_DICTIONARY_HPP

138
src/lib/ruby/audio/alsa.cpp Normal file
View File

@@ -0,0 +1,138 @@
#include <alsa/asoundlib.h>
#include <ruby/ruby.h>
namespace ruby {
#include "alsa.h"
class pAudioALSA {
public:
AudioALSA &self;
struct {
snd_pcm_t *handle;
snd_pcm_format_t format;
snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size;
int channels;
const char *name;
unsigned latency;
} device;
struct {
uint32_t *data;
unsigned length;
} buffer;
struct {
unsigned frequency;
} settings;
bool cap(Audio::Setting setting) {
if(setting == Audio::Frequency) return true;
return false;
}
uintptr_t get(Audio::Setting setting) {
if(setting == Audio::Frequency) return settings.frequency;
return false;
}
bool set(Audio::Setting setting, uintptr_t param) {
if(setting == Audio::Frequency) {
settings.frequency = param;
if(device.handle) {
term();
init();
}
return true;
}
return false;
}
void sample(uint16_t left, uint16_t right) {
if(!device.handle) return;
buffer.data[buffer.length++] = left + (right << 16);
if(buffer.length < device.period_size) return;
uint32_t *buffer_ptr = buffer.data;
do {
snd_pcm_sframes_t written = snd_pcm_writei(device.handle, buffer_ptr, buffer.length);
if(written < 0) {
//no samples written
snd_pcm_recover(device.handle, written, 1);
} else if(written < buffer.length) {
//only some samples written
buffer.length -= written;
buffer_ptr += written;
} else {
//all samples written
buffer.length = 0;
}
} while(buffer.length > 0);
}
bool init() {
if(snd_pcm_open(&device.handle, device.name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
//failed to initialize
term();
return false;
}
if(snd_pcm_set_params(device.handle, device.format, SND_PCM_ACCESS_RW_INTERLEAVED,
device.channels, settings.frequency, 1, device.latency) < 0) {
//failed to set device parameters
term();
return false;
}
if(snd_pcm_get_params(device.handle, &device.buffer_size, &device.period_size) < 0) {
device.period_size = device.latency * 1e-6 * settings.frequency / 4;
}
buffer.data = new uint32_t[device.period_size];
return true;
}
void term() {
if(device.handle) {
snd_pcm_drain(device.handle);
snd_pcm_close(device.handle);
device.handle = 0;
}
if(buffer.data) {
delete[] buffer.data;
buffer.data = 0;
}
}
pAudioALSA(AudioALSA &self_) : self(self_) {
device.handle = 0;
device.format = SND_PCM_FORMAT_S16_LE;
device.channels = 2;
device.name = "default";
device.latency = 100000;
buffer.data = 0;
buffer.length = 0;
settings.frequency = 22050;
}
~pAudioALSA() {
term();
}
};
bool AudioALSA::cap(Setting setting) { return p.cap(setting); }
uintptr_t AudioALSA::get(Setting setting) { return p.get(setting); }
bool AudioALSA::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
void AudioALSA::sample(uint16_t left, uint16_t right) { p.sample(left, right); }
bool AudioALSA::init() { return p.init(); }
void AudioALSA::term() { p.term(); }
AudioALSA::AudioALSA() : p(*new pAudioALSA(*this)) {}
AudioALSA::~AudioALSA() { delete &p; }
} //namespace ruby

23
src/lib/ruby/audio/alsa.h Normal file
View File

@@ -0,0 +1,23 @@
/*
audio.alsa (2008-06-01)
authors: Nach, RedDwarf
*/
class pAudioALSA;
class AudioALSA : public Audio {
public:
bool cap(Setting);
uintptr_t get(Setting);
bool set(Setting, uintptr_t);
void sample(uint16_t left, uint16_t right);
bool init();
void term();
AudioALSA();
~AudioALSA();
private:
pAudioALSA &p;
};

View File

@@ -47,16 +47,23 @@ public:
bool init() {
driver_id = ao_default_driver_id(); //ao_driver_id((const char*)driver)
if(driver_id < 0) driver_id = ao_default_driver_id(); //fallback on default if driver doesn't exist
if(driver_id < 0) return false;
driver_format.bits = 16;
driver_format.channels = 2;
driver_format.rate = settings.frequency;
driver_format.byte_format = AO_FMT_LITTLE;
audio_device = ao_open_live(driver_id, &driver_format, 0);
ao_option *options = 0;
ao_info *di = ao_driver_info(driver_id);
if(!di) return false;
if(!strcmp(di->short_name, "alsa")) {
ao_append_option(&options, "buffer_time", "100000"); //100ms latency (default was 500ms)
}
audio_device = ao_open_live(driver_id, &driver_format, options);
if(!audio_device) return false;
ao_info *di = ao_driver_info(driver_id);
return true;
}

View File

@@ -1,6 +1,6 @@
/*
audio.ao (2007-12-26)
author: Nach
audio.ao (2008-06-01)
authors: Nach, RedDwarf
*/
class pAudioAO;

View File

@@ -92,6 +92,10 @@ void AudioInterface::driver(const char *driver) {
if(!strcmp(driver, "none")) p = new Audio();
#ifdef AUDIO_ALSA
else if(!strcmp(driver, "alsa")) p = new AudioALSA();
#endif
#ifdef AUDIO_AO
else if(!strcmp(driver, "ao")) p = new AudioAO();
#endif
@@ -114,6 +118,8 @@ void AudioInterface::driver(const char *driver) {
p = new AudioDS();
#elif defined(AUDIO_AO)
p = new AudioAO();
#elif defined(AUDIO_ALSA)
p = new AudioALSA();
#elif defined(AUDIO_OPENAL)
p = new AudioOpenAL();
#elif defined(AUDIO_OSS)

View File

@@ -1,6 +1,6 @@
/*
ruby
version: 0.02 (2008-04-06)
version: 0.03 (2008-05-04)
license: public domain
*/

View File

@@ -30,6 +30,10 @@
/* Audio */
#ifdef AUDIO_ALSA
#include <ruby/audio/alsa.cpp>
#endif
#ifdef AUDIO_AO
#include <ruby/audio/ao.cpp>
#endif

6
src/lib/sync.sh Normal file
View File

@@ -0,0 +1,6 @@
rm -r nall
rm -r hiro
rm -r ruby
cp -r ../../../nall ./nall
cp -r ../../../hiro ./hiro
cp -r ../../../ruby ./ruby

View File

@@ -32,9 +32,18 @@ void sBus::map_generic() {
map_generic_sram();
} break;
case Cartridge::SPC7110ROM: {
map(MapDirect, 0x00, 0x00, 0x6000, 0x7fff, spc7110);
map(MapDirect, 0x00, 0x0f, 0x8000, 0xffff, spc7110);
map(MapDirect, 0x30, 0x30, 0x6000, 0x7fff, spc7110);
map(MapDirect, 0x50, 0x50, 0x0000, 0xffff, spc7110);
map(MapDirect, 0x80, 0x8f, 0x8000, 0xffff, spc7110);
map(MapDirect, 0xc0, 0xff, 0x0000, 0xffff, spc7110);
} break;
case Cartridge::BSXROM: {
//full map is dynamically mapped by:
//src/chip/bsx/bsx_cart.cpp : BSXCart::update_memory_map();
//full map is dynamically mapped by:
//src/chip/bsx/bsx_cart.cpp : BSXCart::update_memory_map();
map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::cartrom);
map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::cartrom);
} break;

View File

@@ -330,12 +330,9 @@ void bPPU::cgram_write(uint16 addr, uint8 value) {
}
bPPU::bPPU() {
vram = (uint8*)malloc(65536);
oam = (uint8*)malloc( 544);
cgram = (uint8*)malloc( 512);
memset(vram, 0, 65536);
memset(oam, 0, 544);
memset(cgram, 0, 512);
vram = new(zeromemory) uint8_t[65536];
oam = new(zeromemory) uint8_t[ 544];
cgram = new(zeromemory) uint8_t[ 512];
init_tiledata_cache();
@@ -359,7 +356,7 @@ bPPU::bPPU() {
}
bPPU::~bPPU() {
free(vram);
free(oam);
free(cgram);
delete[] vram;
delete[] oam;
delete[] cgram;
}

View File

@@ -15,19 +15,16 @@ uint8_t* FileReader::read(unsigned length) {
if(length == 0) {
//read the entire file into RAM
data = (uint8*)malloc(filesize);
memset(data, 0, filesize);
data = new(zeromemory) uint8_t[filesize];
if(fp) fread(data, 1, filesize, fp);
} else if(length > filesize) {
//read the entire file into RAM, pad the rest with 0x00s
data = (uint8*)malloc(length);
memset(data, 0, length);
if(fp)fread(data, 1, filesize, fp);
data = new(zeromemory) uint8_t[length];
if(fp) fread(data, 1, filesize, fp);
} else { //filesize >= length
//read only what was requested
data = (uint8*)malloc(length);
memset(data, 0, length);
if(fp)fread(data, 1, length, fp);
data = new(zeromemory) uint8_t[length];
if(fp) fread(data, 1, length, fp);
}
return data;
}
@@ -57,25 +54,5 @@ FileReader::~FileReader() {
fp = 0;
}
}
void FileWriter::write(uint8_t *buffer, unsigned length) {
if(!fp) return;
fwrite(buffer, 1, length, fp);
}
bool FileWriter::ready() {
return (fp != 0);
}
FileWriter::FileWriter(const char *fn) {
fp = fopen(fn, "wb");
}
FileWriter::~FileWriter() {
if(fp) {
fclose(fp);
fp = 0;
}
}
#endif //ifdef READER_CPP

View File

@@ -1,25 +1,13 @@
class FileReader : public Reader {
private:
FILE *fp;
unsigned filesize;
public:
unsigned size();
uint8_t* read(unsigned length = 0);
bool ready();
FileReader(const char *fn);
~FileReader();
};
class FileWriter : public Writer {
private:
FILE *fp;
public:
void write(uint8_t *buffer, unsigned length);
bool ready();
FileWriter(const char *fn);
~FileWriter();
~FileReader();
private:
FILE *fp;
unsigned filesize;
};

View File

@@ -15,19 +15,16 @@ uint8_t* GZReader::read(unsigned length) {
if(length == 0) {
//read the entire file into RAM
data = (uint8*)malloc(filesize);
memset(data, 0, filesize);
if(gp)gzread(gp, data, filesize);
data = new(zeromemory) uint8_t[filesize];
if(gp) gzread(gp, data, filesize);
} else if(length > filesize) {
//read the entire file into RAM, pad the rest with 0x00s
data = (uint8*)malloc(length);
memset(data, 0, length);
if(gp)gzread(gp, data, filesize);
data = new(zeromemory) uint8_t[length];
if(gp) gzread(gp, data, filesize);
} else { //filesize >= length
//read only what was requested
data = (uint8*)malloc(length);
memset(data, 0, length);
if(gp)gzread(gp, data, length);
data = new(zeromemory) uint8_t[length];
if(gp) gzread(gp, data, length);
}
return data;
@@ -40,7 +37,7 @@ bool GZReader::ready() {
GZReader::GZReader(const char *fn) {
gp = 0;
FILE *fp = fopen(fn, "rb");
if(!fp)return;
if(!fp) return;
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
@@ -62,7 +59,7 @@ uint32 gzsize;
fp = 0;
gp = gzopen(fn, "rb");
if(!gp)return;
if(!gp) return;
if(!gzdirect(gp)) {
filesize = gzsize;

View File

@@ -15,12 +15,11 @@ uint8_t* JMAReader::read(unsigned length) {
if(length <= filesize) {
//read the entire file into RAM
data = (uint8_t*)malloc(filesize);
data = new(zeromemory) uint8_t[filesize];
JMAFile.extract_file(cname, data);
} else if(length > filesize) {
//read the entire file into RAM, pad the rest with 0x00s
data = (uint8_t*)malloc(length);
memset(data, 0, length);
data = new(zeromemory) uint8_t[length];
JMAFile.extract_file(cname, data);
}

View File

@@ -13,9 +13,3 @@ public:
virtual uint8_t* read(unsigned length = 0) = 0;
virtual bool ready() { return true; } //can only call read() when ready() returns true
};
class Writer {
public:
virtual void write(uint8_t *buffer, uint32 length) = 0;
virtual bool ready() { return true; }
};

View File

@@ -15,12 +15,11 @@ uint8_t* ZipReader::read(unsigned length) {
if(length <= filesize) {
//read the entire file into RAM
data = (uint8_t*)malloc(filesize);
data = new(zeromemory) uint8_t[filesize];
unzReadCurrentFile(zipfile, data, filesize);
} else if(length > filesize) {
//read the entire file into RAM, pad the rest with 0x00s
data = (uint8_t*)malloc(length);
memset(data, 0, length);
data = new(zeromemory) uint8_t[length];
unzReadCurrentFile(zipfile, data, filesize);
}

View File

@@ -1,19 +1,32 @@
template<int mask>
struct SMPFlag {
uint8 &data;
inline operator bool() const { return data & mask; }
inline SMPFlag& operator=(bool i) { data = (data & ~mask) | (-i & mask); return *this; }
SMPFlag(uint8 &data_) : data(data_) {}
};
class SMPRegFlags {
public:
union {
uint8 data;
struct {
bool order_msb8(n:1, v:1, p:1, b:1, h:1, i:1, z:1, c:1);
};
};
public:
uint8 data;
SMPFlag<0x80> n;
SMPFlag<0x40> v;
SMPFlag<0x20> p;
SMPFlag<0x10> b;
SMPFlag<0x08> h;
SMPFlag<0x04> i;
SMPFlag<0x02> z;
SMPFlag<0x01> c;
inline operator unsigned() const { return data; }
template<typename T> inline unsigned operator = (const T i) { data = i; return data; }
template<typename T> inline unsigned operator |= (const T i) { data |= i; return data; }
template<typename T> inline unsigned operator ^= (const T i) { data ^= i; return data; }
template<typename T> inline unsigned operator &= (const T i) { data &= i; return data; }
inline unsigned operator = (unsigned i) { data = i; return data; }
inline unsigned operator |= (unsigned i) { data |= i; return data; }
inline unsigned operator ^= (unsigned i) { data ^= i; return data; }
inline unsigned operator &= (unsigned i) { data &= i; return data; }
SMPRegFlags() : data(0) {}
SMPRegFlags() : data(0), n(data), v(data), p(data), b(data), h(data), i(data), z(data), c(data) {}
};
class SMPRegs {
@@ -24,5 +37,6 @@ public:
struct { uint8 order_lsb2(a, y); };
};
uint8 x, sp;
SMPRegFlags p;
SMPRegFlags p;
SMPRegs() : pc(0), ya(0), x(0), sp(0) {}
};

View File

@@ -64,7 +64,7 @@ clrv(0xe0) {
notc(0xed) {
1:op_io();
2:op_io();
regs.p.c ^= 1;
regs.p.c = !regs.p.c;
}
ei(0xa0, 1),

View File

@@ -93,7 +93,7 @@ case 0xe0: {
case 0xed: {
op_io();
op_io();
regs.p.c ^= 1;
regs.p.c = !regs.p.c;
} break;
//ei

View File

@@ -1,125 +1,125 @@
#ifdef SSMP_CPP
uint8 sSMP::op_adc(uint8 x, uint8 y) {
int16 r = x + y + regs.p.c;
regs.p.n = !!(r & 0x80);
regs.p.v = !!(~(x ^ y) & (y ^ (uint8)r) & 0x80);
regs.p.h = !!((x ^ y ^ (uint8)r) & 0x10);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r > 0xff);
int r = x + y + regs.p.c;
regs.p.n = r & 0x80;
regs.p.v = ~(x ^ y) & (x ^ r) & 0x80;
regs.p.h = (x ^ y ^ r) & 0x10;
regs.p.z = (uint8)r == 0;
regs.p.c = r > 0xff;
return r;
}
uint16 sSMP::op_addw(uint16 x, uint16 y) {
uint16 r;
uint16 r;
regs.p.c = 0;
r = op_adc(x, y);
r |= op_adc(x >> 8, y >> 8) << 8;
regs.p.z = (r == 0);
regs.p.z = r == 0;
return r;
}
uint8 sSMP::op_and(uint8 x, uint8 y) {
x &= y;
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 sSMP::op_cmp(uint8 x, uint8 y) {
int16 r = x - y;
regs.p.n = !!(r & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r >= 0);
int r = x - y;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
return x;
}
uint16 sSMP::op_cmpw(uint16 x, uint16 y) {
int32 r = x - y;
regs.p.n = !!(r & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.c = (r >= 0);
int r = x - y;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
return x;
}
uint8 sSMP::op_eor(uint8 x, uint8 y) {
x ^= y;
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 sSMP::op_or(uint8 x, uint8 y) {
x |= y;
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 sSMP::op_sbc(uint8 x, uint8 y) {
int16 r = x - y - !regs.p.c;
regs.p.n = !!(r & 0x80);
regs.p.v = !!((x ^ y) & (x ^ (uint8)r) & 0x80);
regs.p.h = !((x ^ y ^ (uint8)r) & 0x10);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r >= 0);
int r = x - y - !regs.p.c;
regs.p.n = r & 0x80;
regs.p.v = (x ^ y) & (x ^ r) & 0x80;
regs.p.h = !((x ^ y ^ r) & 0x10);
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
return r;
}
uint16 sSMP::op_subw(uint16 x, uint16 y) {
uint16 r;
uint16 r;
regs.p.c = 1;
r = op_sbc(x, y);
r |= op_sbc(x >> 8, y >> 8) << 8;
regs.p.z = (r == 0);
regs.p.z = r == 0;
return r;
}
uint8 sSMP::op_inc(uint8 x) {
x++;
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 sSMP::op_dec(uint8 x) {
x--;
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 sSMP::op_asl(uint8 x) {
regs.p.c = !!(x & 0x80);
regs.p.c = x & 0x80;
x <<= 1;
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 sSMP::op_lsr(uint8 x) {
regs.p.c = !!(x & 0x01);
regs.p.c = x & 0x01;
x >>= 1;
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 sSMP::op_rol(uint8 x) {
uint8 carry = (uint8)regs.p.c;
regs.p.c = !!(x & 0x80);
unsigned carry = (unsigned)regs.p.c;
regs.p.c = x & 0x80;
x = (x << 1) | carry;
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}
uint8 sSMP::op_ror(uint8 x) {
uint8 carry = (uint8)regs.p.c << 7;
regs.p.c = !!(x & 0x01);
unsigned carry = (unsigned)regs.p.c << 7;
regs.p.c = x & 0x01;
x = carry | (x >> 1);
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
regs.p.n = x & 0x80;
regs.p.z = x == 0;
return x;
}

View File

@@ -7,6 +7,7 @@ BSXCart bsxcart;
BSXFlash bsxflash;
SRTC srtc;
SDD1 sdd1;
SPC7110 spc7110;
Cx4 cx4;
DSP1 dsp1;
DSP2 dsp2;
@@ -34,6 +35,7 @@ void SNES::init() {
bsxflash.init();
srtc.init();
sdd1.init();
spc7110.init();
cx4.init();
dsp1.init();
dsp2.init();
@@ -67,6 +69,7 @@ void SNES::power() {
if(cartridge.info.bsxflash) bsxflash.power();
if(cartridge.info.srtc) srtc.power();
if(cartridge.info.sdd1) sdd1.power();
if(cartridge.info.spc7110) spc7110.power();
if(cartridge.info.cx4) cx4.power();
if(cartridge.info.dsp1) dsp1.power();
if(cartridge.info.dsp2) dsp2.power();
@@ -87,6 +90,7 @@ void SNES::power() {
if(cartridge.info.bsxflash) bsxflash.enable();
if(cartridge.info.srtc) srtc.enable();
if(cartridge.info.sdd1) sdd1.enable();
if(cartridge.info.spc7110) spc7110.enable();
if(cartridge.info.cx4) cx4.enable();
if(cartridge.info.dsp1) dsp1.enable();
if(cartridge.info.dsp2) dsp2.enable();
@@ -112,6 +116,7 @@ void SNES::reset() {
if(cartridge.info.bsxflash) bsxflash.reset();
if(cartridge.info.srtc) srtc.reset();
if(cartridge.info.sdd1) sdd1.reset();
if(cartridge.info.spc7110) spc7110.reset();
if(cartridge.info.cx4) cx4.reset();
if(cartridge.info.dsp1) dsp1.reset();
if(cartridge.info.dsp2) dsp2.reset();

View File

@@ -58,10 +58,9 @@ void Tracer::enable(bool en) {
void Tracer::cpuopmask_enable(bool en) {
if(en == true && cpuopmask_enabled() == false) {
settings.cpuopmasktbl = (uint8*)malloc(0x200000);
memset(settings.cpuopmasktbl, 0x00, 0x200000);
settings.cpuopmasktbl = new(zeromemory) uint8_t[0x200000];
} else if(en == false && cpuopmask_enabled() == true) {
safe_free(settings.cpuopmasktbl);
delete[] settings.cpuopmasktbl;
}
settings.cpuopmask = en;
@@ -69,10 +68,9 @@ void Tracer::cpuopmask_enable(bool en) {
void Tracer::smpopmask_enable(bool en) {
if(en == true && smpopmask_enabled() == false) {
settings.smpopmasktbl = (uint8*)malloc(0x2000);
memset(settings.smpopmasktbl, 0x00, 0x2000);
settings.smpopmasktbl = new(zeromemory) uint8_t[0x2000];
} else if(en == false && smpopmask_enabled() == true) {
safe_free(settings.smpopmasktbl);
delete[] settings.smpopmasktbl;
}
settings.smpopmask = en;

View File

@@ -1,40 +1,40 @@
const char AboutWindow::about_text[1024] = ""
"bsnes -- version " BSNES_VERSION "\n"
"Author: byuu\n"
"Project began: October 14th, 2004";
const char AboutWindow::contributors_text[1024] =
"Contributors:\n"
" anomie, blargg, DMV27, GIGO, kode54, Nach,\n"
" Overload, Richard Bannister, TRAC, zones";
uintptr_t AboutWindow::close(Event) {
hide();
return false;
}
void AboutWindow::setup() {
create(Window::AutoCenter, 350, 125, "About bsnes ...");
set_icon(48, 48, (uint32_t*)resource::icon48);
icon.create(0, 48, 48);
about.create(0, 287, 48, about_text);
contributors.create(0, 340, 48, contributors_text);
attach(icon, 5, 5);
attach(about, 58, 5);
create(Window::AutoCenter, 360, 135, translate["About bsnes ..."]);
set_icon(48, 48, (uint32_t*)resource::icon48);
icon.create(0, 48, 48);
about.create(0, 225, 48, string()
<< "bsnes -- " << translate["Version"] << " " << BSNES_VERSION "\n"
<< translate["Author"] << ": byuu\n"
<< translate["Project began: October 14th, 2004"]
);
contributors.create(0, 350, 75, string()
<< translate["Contributors:"] << "\n"
<< " Andreas Naive, anomie, blargg, DMV27, GIGO, kode54,\n"
<< " neviksti, Nach, Overload, Richard Bannister, TRAC, zones\n"
<< "\n"
<< translate["Localization by: byuu"]
);
attach(icon, 5, 5);
attach(about, 58, 5);
attach(contributors, 5, 58);
on_close = bind(&AboutWindow::close, this);
uint8_t *buffer = new uint8_t[48 * 48 * 4];
memcpy(buffer, resource::icon48, 48 * 48 * 4);
for(unsigned i = 0; i < 48 * 48; i++) {
uint8_t alpha = buffer[i * 4 + 3];
buffer[i * 4 + 2] = uint8_t(1.0 / 256.0 * alpha * buffer[i * 4 + 2]);
buffer[i * 4 + 1] = uint8_t(1.0 / 256.0 * alpha * buffer[i * 4 + 1]);
buffer[i * 4 + 0] = uint8_t(1.0 / 256.0 * alpha * buffer[i * 4 + 0]);
}
memcpy(icon.buffer(), buffer, 48 * 48 * 4);
delete[] buffer;
on_close = bind(&AboutWindow::close, this);
uint8_t *buffer = new uint8_t[48 * 48 * 4];
memcpy(buffer, resource::icon48, 48 * 48 * 4);
for(unsigned i = 0; i < 48 * 48; i++) {
uint8_t alpha = buffer[i * 4 + 3];
buffer[i * 4 + 2] = uint8_t(1.0 / 256.0 * alpha * buffer[i * 4 + 2]);
buffer[i * 4 + 1] = uint8_t(1.0 / 256.0 * alpha * buffer[i * 4 + 1]);
buffer[i * 4 + 0] = uint8_t(1.0 / 256.0 * alpha * buffer[i * 4 + 0]);
}
memcpy(icon.buffer(), buffer, 48 * 48 * 4);
delete[] buffer;
}

View File

@@ -8,13 +8,7 @@ bool MainWindow::input_ready() {
}
uintptr_t MainWindow::close(Event) {
app.term = true;
window_about.hide();
window_message.hide();
window_settings.hide();
window_bsxloader.hide();
window_stloader.hide();
hide();
event::quit();
return false;
}
@@ -26,14 +20,14 @@ uintptr_t MainWindow::event(Event e) {
if(e.widget == &menu_file_load_bsx) {
window_bsxloader.mode = BSXLoaderWindow::ModeBSX;
window_bsxloader.set_text("Load BS-X Cartridge");
window_bsxloader.set_text(translate["Load BS-X Cartridge"]);
window_bsxloader.tbase.set_text(config::path.bsx);
window_bsxloader.focus();
}
if(e.widget == &menu_file_load_bsc) {
window_bsxloader.mode = BSXLoaderWindow::ModeBSC;
window_bsxloader.set_text("Load BS-X Slotted Cartridge");
window_bsxloader.set_text(translate["Load BS-X Slotted Cartridge"]);
window_bsxloader.tbase.set_text("");
window_bsxloader.focus();
}
@@ -59,53 +53,50 @@ uintptr_t MainWindow::event(Event e) {
event(Event(Event::Close));
}
if(locked == false) {
//set locked to true to update below menu item check statuses without triggering events
if(e.widget == &menu_settings_videomode_1x) { event::update_multiplier(1); }
if(e.widget == &menu_settings_videomode_2x) { event::update_multiplier(2); }
if(e.widget == &menu_settings_videomode_3x) { event::update_multiplier(3); }
if(e.widget == &menu_settings_videomode_4x) { event::update_multiplier(4); }
if(e.widget == &menu_settings_videomode_5x) { event::update_multiplier(5); }
if(e.widget == &menu_settings_videomode_1x) { event::update_multiplier(1); }
if(e.widget == &menu_settings_videomode_2x) { event::update_multiplier(2); }
if(e.widget == &menu_settings_videomode_3x) { event::update_multiplier(3); }
if(e.widget == &menu_settings_videomode_4x) { event::update_multiplier(4); }
if(e.widget == &menu_settings_videomode_5x) { event::update_multiplier(5); }
if(e.widget == &menu_settings_videomode_aspect_correction) {
event::update_aspect_correction(menu_settings_videomode_aspect_correction.checked());
}
if(e.widget == &menu_settings_videomode_ntsc) { event::update_region(0); }
if(e.widget == &menu_settings_videomode_pal) { event::update_region(1); }
if(e.widget == &menu_settings_videofilter_hwpoint) { event::update_hardware_filter(0); }
if(e.widget == &menu_settings_videofilter_hwlinear) { event::update_hardware_filter(1); }
if(e.widget == &menu_settings_videofilter_swnone) { event::update_software_filter(0); }
if(e.widget == &menu_settings_videofilter_swscanline) { event::update_software_filter(1); }
if(e.widget == &menu_settings_videofilter_swscale2x) { event::update_software_filter(2); }
if(e.widget == &menu_settings_videofilter_swhq2x) { event::update_software_filter(3); }
if(e.widget == &menu_settings_videofilter_swntsc) { event::update_software_filter(4); }
if(e.widget == &menu_settings_videoframeskip_0) { config::video.frameskip = 0; }
if(e.widget == &menu_settings_videoframeskip_1) { config::video.frameskip = 1; }
if(e.widget == &menu_settings_videoframeskip_2) { config::video.frameskip = 2; }
if(e.widget == &menu_settings_videoframeskip_3) { config::video.frameskip = 3; }
if(e.widget == &menu_settings_videoframeskip_4) { config::video.frameskip = 4; }
if(e.widget == &menu_settings_videoframeskip_5) { config::video.frameskip = 5; }
if(e.widget == &menu_settings_videoframeskip_6) { config::video.frameskip = 6; }
if(e.widget == &menu_settings_videoframeskip_7) { config::video.frameskip = 7; }
if(e.widget == &menu_settings_videoframeskip_8) { config::video.frameskip = 8; }
if(e.widget == &menu_settings_videoframeskip_9) { config::video.frameskip = 9; }
if(e.widget == &menu_settings_mute) {
config::audio.mute = menu_settings_mute.checked();
}
if(e.widget == &menu_settings_speedreg_disabled) { event::update_speed_regulation(0); }
if(e.widget == &menu_settings_speedreg_slowest) { event::update_speed_regulation(1); }
if(e.widget == &menu_settings_speedreg_slow) { event::update_speed_regulation(2); }
if(e.widget == &menu_settings_speedreg_normal) { event::update_speed_regulation(3); }
if(e.widget == &menu_settings_speedreg_fast) { event::update_speed_regulation(4); }
if(e.widget == &menu_settings_speedreg_fastest) { event::update_speed_regulation(5); }
if(e.widget == &menu_settings_videomode_aspect_correction) {
event::update_aspect_correction(menu_settings_videomode_aspect_correction.checked());
}
if(e.widget == &menu_settings_videomode_ntsc) { event::update_region(0); }
if(e.widget == &menu_settings_videomode_pal) { event::update_region(1); }
if(e.widget == &menu_settings_videofilter_hwpoint) { event::update_hardware_filter(0); }
if(e.widget == &menu_settings_videofilter_hwlinear) { event::update_hardware_filter(1); }
if(e.widget == &menu_settings_videofilter_swnone) { event::update_software_filter(0); }
if(e.widget == &menu_settings_videofilter_swscanline) { event::update_software_filter(1); }
if(e.widget == &menu_settings_videofilter_swscale2x) { event::update_software_filter(2); }
if(e.widget == &menu_settings_videofilter_swhq2x) { event::update_software_filter(3); }
if(e.widget == &menu_settings_videofilter_swntsc) { event::update_software_filter(4); }
if(e.widget == &menu_settings_videoframeskip_0) { event::update_frameskip(0); }
if(e.widget == &menu_settings_videoframeskip_1) { event::update_frameskip(1); }
if(e.widget == &menu_settings_videoframeskip_2) { event::update_frameskip(2); }
if(e.widget == &menu_settings_videoframeskip_3) { event::update_frameskip(3); }
if(e.widget == &menu_settings_videoframeskip_4) { event::update_frameskip(4); }
if(e.widget == &menu_settings_videoframeskip_5) { event::update_frameskip(5); }
if(e.widget == &menu_settings_videoframeskip_6) { event::update_frameskip(6); }
if(e.widget == &menu_settings_videoframeskip_7) { event::update_frameskip(7); }
if(e.widget == &menu_settings_videoframeskip_8) { event::update_frameskip(8); }
if(e.widget == &menu_settings_videoframeskip_9) { event::update_frameskip(9); }
if(e.widget == &menu_settings_mute) {
config::audio.mute = menu_settings_mute.checked();
}
if(e.widget == &menu_settings_emuspeed_slowest) { event::update_emulation_speed(0); }
if(e.widget == &menu_settings_emuspeed_slow) { event::update_emulation_speed(1); }
if(e.widget == &menu_settings_emuspeed_normal) { event::update_emulation_speed(2); }
if(e.widget == &menu_settings_emuspeed_fast) { event::update_emulation_speed(3); }
if(e.widget == &menu_settings_emuspeed_fastest) { event::update_emulation_speed(4); }
if(e.widget == &menu_settings_emuspeed_disabled) { event::update_emulation_speed(5); }
if(e.widget == &menu_settings_config) { window_settings.show(); }
if(e.widget == &menu_misc_logaudio) {
@@ -130,53 +121,52 @@ uintptr_t MainWindow::block(Event) {
}
void MainWindow::setup() {
locked = true;
create(Window::AutoCenter, 256, 224, BSNES_TITLE);
set_background_color(0, 0, 0);
set_icon(48, 48, (uint32_t*)resource::icon48);
MenuRadioItemGroup group;
attach(menu_file.create("File"));
menu_file.attach(menu_file_load.create("Load Cartridge ..."));
menu_file.attach(menu_file_load_special.create("Load Special"));
menu_file_load_special.attach(menu_file_load_bsx.create("Load BS-X Cartridge ..."));
menu_file_load_special.attach(menu_file_load_bsc.create("Load BS-X Slotted Cartridge ..."));
menu_file_load_special.attach(menu_file_load_st.create("Load ST Cartridge ..."));
menu_file.attach(menu_file_unload.create("Unload Cartridge"));
MenuRadioItemGroup group;
attach(menu_file.create(translate["System"]));
menu_file.attach(menu_file_load.create(string() << translate["Load Cartridge"] << " ..."));
menu_file.attach(menu_file_load_special.create(translate["Load Special"]));
menu_file_load_special.attach(menu_file_load_bsx.create(string() << translate["Load BS-X Cartridge"] << " ..."));
menu_file_load_special.attach(menu_file_load_bsc.create(string() << translate["Load BS-X Slotted Cartridge"] << " ..."));
menu_file_load_special.attach(menu_file_load_st.create(string() << translate["Load Sufami Turbo Cartridge"] << " ..."));
menu_file.attach(menu_file_unload.create(translate["Unload Cartridge"]));
menu_file.attach(menu_file_sep1.create());
menu_file.attach(menu_file_reset.create("Reset System"));
menu_file.attach(menu_file_power.create("Power Cycle System"));
menu_file.attach(menu_file_reset.create(translate["Reset"]));
menu_file_power.create(translate["Power Cycle"]);
if(config::advanced.enable) menu_file.attach(menu_file_power);
menu_file.attach(menu_file_sep2.create());
menu_file.attach(menu_file_exit.create("Exit"));
menu_file.attach(menu_file_exit.create(translate["Exit"]));
attach(menu_settings.create("Settings"));
menu_settings.attach(menu_settings_videomode.create("Video Mode"));
attach(menu_settings.create(translate["Settings"]));
menu_settings.attach(menu_settings_videomode.create(translate["Video Mode"]));
group.add(&menu_settings_videomode_1x);
group.add(&menu_settings_videomode_2x);
group.add(&menu_settings_videomode_3x);
group.add(&menu_settings_videomode_4x);
group.add(&menu_settings_videomode_5x);
menu_settings_videomode.attach(menu_settings_videomode_1x.create(group, "Scale 1x"));
menu_settings_videomode.attach(menu_settings_videomode_2x.create(group, "Scale 2x"));
menu_settings_videomode.attach(menu_settings_videomode_3x.create(group, "Scale 3x"));
menu_settings_videomode.attach(menu_settings_videomode_4x.create(group, "Scale 4x"));
menu_settings_videomode.attach(menu_settings_videomode_5x.create(group, "Scale 5x"));
menu_settings_videomode.attach(menu_settings_videomode_1x.create(group, translate["Scale 1x"]));
menu_settings_videomode.attach(menu_settings_videomode_2x.create(group, translate["Scale 2x"]));
menu_settings_videomode.attach(menu_settings_videomode_3x.create(group, translate["Scale 3x"]));
menu_settings_videomode.attach(menu_settings_videomode_4x.create(group, translate["Scale 4x"]));
menu_settings_videomode.attach(menu_settings_videomode_5x.create(group, translate["Scale 5x"]));
group.reset();
menu_settings_videomode.attach(menu_settings_videomode_sep1.create());
menu_settings_videomode.attach(menu_settings_videomode_aspect_correction.create("Correct Aspect Ratio"));
menu_settings_videomode.attach(menu_settings_videomode_aspect_correction.create(translate["Correct Aspect Ratio"]));
menu_settings_videomode.attach(menu_settings_videomode_sep2.create());
group.add(&menu_settings_videomode_ntsc);
group.add(&menu_settings_videomode_pal);
menu_settings_videomode.attach(menu_settings_videomode_ntsc.create(group, "NTSC"));
menu_settings_videomode.attach(menu_settings_videomode_pal.create(group, "PAL"));
menu_settings_videomode.attach(menu_settings_videomode_ntsc.create(group, translate["NTSC"]));
menu_settings_videomode.attach(menu_settings_videomode_pal.create(group, translate["PAL"]));
group.reset();
menu_settings.attach(menu_settings_videofilter.create("Video Filter"));
menu_settings.attach(menu_settings_videofilter.create(translate["Video Filter"]));
group.add(&menu_settings_videofilter_hwpoint);
group.add(&menu_settings_videofilter_hwlinear);
menu_settings_videofilter.attach(menu_settings_videofilter_hwpoint.create(group, "Point"));
menu_settings_videofilter.attach(menu_settings_videofilter_hwlinear.create(group, "Linear"));
menu_settings_videofilter.attach(menu_settings_videofilter_hwpoint.create(group, translate["Point"]));
menu_settings_videofilter.attach(menu_settings_videofilter_hwlinear.create(group, translate["Linear"]));
group.reset();
menu_settings_videofilter.attach(menu_settings_videofilter_sep1.create());
group.add(&menu_settings_videofilter_swnone);
@@ -184,14 +174,14 @@ MenuRadioItemGroup group;
group.add(&menu_settings_videofilter_swscale2x);
group.add(&menu_settings_videofilter_swhq2x);
group.add(&menu_settings_videofilter_swntsc);
menu_settings_videofilter.attach(menu_settings_videofilter_swnone.create(group, "None"));
menu_settings_videofilter.attach(menu_settings_videofilter_swscanline.create(group, "Scanline"));
menu_settings_videofilter.attach(menu_settings_videofilter_swscale2x.create(group, "Scale2x"));
menu_settings_videofilter.attach(menu_settings_videofilter_swhq2x.create(group, "HQ2x"));
menu_settings_videofilter.attach(menu_settings_videofilter_swntsc.create(group, "NTSC"));
menu_settings_videofilter.attach(menu_settings_videofilter_swnone.create(group, translate["None"]));
menu_settings_videofilter.attach(menu_settings_videofilter_swscanline.create(group, translate["Scanline"]));
menu_settings_videofilter.attach(menu_settings_videofilter_swscale2x.create(group, translate["Scale2x"]));
menu_settings_videofilter.attach(menu_settings_videofilter_swhq2x.create(group, translate["HQ2x"]));
menu_settings_videofilter.attach(menu_settings_videofilter_swntsc.create(group, translate["NTSC"]));
group.reset();
menu_settings.attach(menu_settings_videoframeskip.create("Video Frameskip"));
menu_settings.attach(menu_settings_videoframeskip.create(translate["Video Frameskip"]));
group.add(&menu_settings_videoframeskip_0);
group.add(&menu_settings_videoframeskip_1);
group.add(&menu_settings_videoframeskip_2);
@@ -202,47 +192,49 @@ MenuRadioItemGroup group;
group.add(&menu_settings_videoframeskip_7);
group.add(&menu_settings_videoframeskip_8);
group.add(&menu_settings_videoframeskip_9);
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_0.create(group, "0"));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_sep1.create());
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_1.create(group, "1"));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_2.create(group, "2"));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_3.create(group, "3"));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_4.create(group, "4"));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_5.create(group, "5"));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_6.create(group, "6"));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_7.create(group, "7"));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_8.create(group, "8"));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_9.create(group, "9"));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_0.create(group, translate["0"]));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_1.create(group, translate["1"]));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_2.create(group, translate["2"]));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_3.create(group, translate["3"]));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_4.create(group, translate["4"]));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_5.create(group, translate["5"]));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_6.create(group, translate["6"]));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_7.create(group, translate["7"]));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_8.create(group, translate["8"]));
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_9.create(group, translate["9"]));
group.reset();
menu_settings.attach(menu_settings_sep1.create());
menu_settings.attach(menu_settings_mute.create("Mute Sound Output"));
menu_settings.attach(menu_settings_mute.create(translate["Mute Audio Output"]));
menu_settings.attach(menu_settings_sep2.create());
menu_settings.attach(menu_settings_speedreg.create("Speed Regulation"));
group.add(&menu_settings_speedreg_disabled);
group.add(&menu_settings_speedreg_slowest);
group.add(&menu_settings_speedreg_slow);
group.add(&menu_settings_speedreg_normal);
group.add(&menu_settings_speedreg_fast);
group.add(&menu_settings_speedreg_fastest);
menu_settings_speedreg.attach(menu_settings_speedreg_disabled.create(group, "Disabled"));
menu_settings_speedreg.attach(menu_settings_speedreg_sep1.create());
menu_settings_speedreg.attach(menu_settings_speedreg_slowest.create(group, "Slowest"));
menu_settings_speedreg.attach(menu_settings_speedreg_slow.create(group, "Slow"));
menu_settings_speedreg.attach(menu_settings_speedreg_normal.create(group, "Normal"));
menu_settings_speedreg.attach(menu_settings_speedreg_fast.create(group, "Fast"));
menu_settings_speedreg.attach(menu_settings_speedreg_fastest.create(group, "Fastest"));
menu_settings.attach(menu_settings_emuspeed.create(translate["Emulation Speed"]));
group.add(&menu_settings_emuspeed_slowest);
group.add(&menu_settings_emuspeed_slow);
group.add(&menu_settings_emuspeed_normal);
group.add(&menu_settings_emuspeed_fast);
group.add(&menu_settings_emuspeed_fastest);
group.add(&menu_settings_emuspeed_disabled);
menu_settings_emuspeed.attach(menu_settings_emuspeed_slowest.create(group, translate["50%"]));
menu_settings_emuspeed.attach(menu_settings_emuspeed_slow.create(group, translate["75%"]));
menu_settings_emuspeed.attach(menu_settings_emuspeed_normal.create(group, translate["100%"]));
menu_settings_emuspeed.attach(menu_settings_emuspeed_fast.create(group, translate["150%"]));
menu_settings_emuspeed.attach(menu_settings_emuspeed_fastest.create(group, translate["200%"]));
menu_settings_emuspeed.attach(menu_settings_emuspeed_disabled.create(group, translate["Uncapped"]));
group.reset();
menu_settings.attach(menu_settings_sep3.create());
menu_settings.attach(menu_settings_config.create("Configuration ..."));
menu_settings.attach(menu_settings_config.create(string() << translate["Configuration"] << " ..."));
attach(menu_misc.create("Misc"));
menu_misc.attach(menu_misc_logaudio.create("Log Audio Data"));
menu_misc.attach(menu_misc_showstatus.create("Show Statusbar"));
attach(menu_misc.create(translate["Misc"]));
menu_misc.attach(menu_misc_logaudio.create(translate["Log Audio Data"]));
menu_misc.attach(menu_misc_showstatus.create(translate["Show Statusbar"]));
menu_misc.attach(menu_misc_sep1.create());
menu_misc.attach(menu_misc_about.create("About ..."));
menu_misc.attach(menu_misc_about.create(string() << translate["About"] << " ..."));
menu_file_unload.disable();
menu_file_reset.disable();
menu_file_power.disable();
view.create(0, 256, 224);
attach(view, 0, 0);
@@ -289,12 +281,12 @@ MenuRadioItemGroup group;
menu_settings_videoframeskip_9.on_tick =
menu_settings_mute.on_tick =
menu_settings_speedreg_disabled.on_tick =
menu_settings_speedreg_slowest.on_tick =
menu_settings_speedreg_slow.on_tick =
menu_settings_speedreg_normal.on_tick =
menu_settings_speedreg_fast.on_tick =
menu_settings_speedreg_fastest.on_tick =
menu_settings_emuspeed_slowest.on_tick =
menu_settings_emuspeed_slow.on_tick =
menu_settings_emuspeed_normal.on_tick =
menu_settings_emuspeed_fast.on_tick =
menu_settings_emuspeed_fastest.on_tick =
menu_settings_emuspeed_disabled.on_tick =
menu_settings_config.on_tick =
menu_misc_logaudio.on_tick =
@@ -302,10 +294,11 @@ MenuRadioItemGroup group;
menu_misc_about.on_tick =
bind(&MainWindow::event, this);
if(config::misc.status_enable) status.show();
}
void MainWindow::update_menu_settings() {
locked = true;
void MainWindow::sync() {
event::load_video_settings();
switch(event::video_settings.multiplier) { default:
@@ -338,16 +331,27 @@ void MainWindow::update_menu_settings() {
menu_settings_mute.check(config::audio.mute);
switch(config::system.speed_regulation) {
case 0: menu_settings_speedreg_disabled.check(); break;
case 1: menu_settings_speedreg_slowest.check(); break;
case 2: menu_settings_speedreg_slow.check(); break;
case 3: menu_settings_speedreg_normal.check(); break;
case 4: menu_settings_speedreg_fast.check(); break;
case 5: menu_settings_speedreg_fastest.check(); break;
switch(config::video.frameskip) {
case 0: menu_settings_videoframeskip_0.check(); break;
case 1: menu_settings_videoframeskip_1.check(); break;
case 2: menu_settings_videoframeskip_2.check(); break;
case 3: menu_settings_videoframeskip_3.check(); break;
case 4: menu_settings_videoframeskip_4.check(); break;
case 5: menu_settings_videoframeskip_5.check(); break;
case 6: menu_settings_videoframeskip_6.check(); break;
case 7: menu_settings_videoframeskip_7.check(); break;
case 8: menu_settings_videoframeskip_8.check(); break;
case 9: menu_settings_videoframeskip_9.check(); break;
}
switch(config::system.emulation_speed) {
case 0: menu_settings_emuspeed_slowest.check(); break;
case 1: menu_settings_emuspeed_slow.check(); break;
case 2: menu_settings_emuspeed_normal.check(); break;
case 3: menu_settings_emuspeed_fast.check(); break;
case 4: menu_settings_emuspeed_fastest.check(); break;
case 5: menu_settings_emuspeed_disabled.check(); break;
}
menu_misc_showstatus.check(config::misc.status_enable);
locked = false;
}

View File

@@ -36,7 +36,6 @@ public:
MenuRadioItem menu_settings_videofilter_swntsc;
MenuGroup menu_settings_videoframeskip;
MenuRadioItem menu_settings_videoframeskip_0;
MenuSeparator menu_settings_videoframeskip_sep1;
MenuRadioItem menu_settings_videoframeskip_1;
MenuRadioItem menu_settings_videoframeskip_2;
MenuRadioItem menu_settings_videoframeskip_3;
@@ -49,14 +48,13 @@ public:
MenuSeparator menu_settings_sep1;
MenuCheckItem menu_settings_mute;
MenuSeparator menu_settings_sep2;
MenuGroup menu_settings_speedreg;
MenuRadioItem menu_settings_speedreg_disabled;
MenuSeparator menu_settings_speedreg_sep1;
MenuRadioItem menu_settings_speedreg_slowest;
MenuRadioItem menu_settings_speedreg_slow;
MenuRadioItem menu_settings_speedreg_normal;
MenuRadioItem menu_settings_speedreg_fast;
MenuRadioItem menu_settings_speedreg_fastest;
MenuGroup menu_settings_emuspeed;
MenuRadioItem menu_settings_emuspeed_slowest;
MenuRadioItem menu_settings_emuspeed_slow;
MenuRadioItem menu_settings_emuspeed_normal;
MenuRadioItem menu_settings_emuspeed_fast;
MenuRadioItem menu_settings_emuspeed_fastest;
MenuRadioItem menu_settings_emuspeed_disabled;
MenuSeparator menu_settings_sep3;
MenuItem menu_settings_config;
@@ -68,11 +66,10 @@ public:
Canvas view;
bool locked;
bool input_ready();
void setup();
void update_menu_settings();
void sync();
uintptr_t close(Event);
uintptr_t event(Event);
uintptr_t block(Event);

View File

@@ -5,16 +5,16 @@ uintptr_t MessageWindow::close(Event) {
void MessageWindow::setup() {
create(Window::AutoCenter, 400, 100, "");
message.create(0, 390, 60, "Test\nMessage");
ok.create(0, 100, 30, "Ok");
message.create(0, 390, 60, "");
ok.create(0, 100, 25, translate["Ok"]);
attach(message, 5, 5);
attach(ok, 295, 65);
attach(ok, 295, 70);
on_close = ok.on_tick = bind(&MessageWindow::close, this);
}
void MessageWindow::show(const char *message_, const char *title_) {
message.set_text(message_);
set_text(title_);
set_text(translate[title_]);
focus();
}

View File

@@ -1,10 +1,11 @@
namespace config {
char filename[PATH_MAX + 16] = "bsnes.cfg";
char bsnes_cfg[PATH_MAX] = "";
char locale_cfg[PATH_MAX] = "";
struct System {
static string_setting video, audio, input;
static integral_setting speed_regulation;
static integral_setting emulation_speed;
static integral_setting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma;
} system;
@@ -12,15 +13,15 @@ string_setting System::video(config(), "system.video", "Video hardware interface
string_setting System::audio(config(), "system.audio", "Audio hardware interface", "");
string_setting System::input(config(), "system.input", "Input hardware interface", "");
integral_setting System::speed_regulation(config(), "system.speed_regulation",
"Speed regulation setting\n"
"0 = Disabled\n"
"1 = Slowest\n"
"2 = Slow\n"
"3 = Normal\n"
"4 = Fast\n"
"5 = Fastest",
integral_setting::decimal, 3);
integral_setting System::emulation_speed(config(), "system.emulation_speed",
"Relative speed of emulator compared to SNES hardware\n"
"0 = 50%\n"
"1 = 75%\n"
"2 = 100%\n"
"3 = 150%\n"
"4 = 200%\n"
"5 = Uncapped",
integral_setting::decimal, 2);
integral_setting System::gamma_ramp(config(), "system.colorfilter.gamma_ramp",
"Use precalculated TV-style gamma ramp", integral_setting::boolean, true);
@@ -117,7 +118,12 @@ struct Input {
static string_setting load;
static string_setting pause;
static string_setting reset;
static string_setting power;
static string_setting power;
static string_setting quit;
static string_setting speed_decrease;
static string_setting speed_increase;
static string_setting frameskip_decrease;
static string_setting frameskip_increase;
static string_setting toggle_fullscreen;
static string_setting toggle_menubar;
static string_setting toggle_statusbar;
@@ -164,13 +170,18 @@ string_setting Input::Joypad2::r (config(), "input.joypad2.r", "", "l")
string_setting Input::Joypad2::select(config(), "input.joypad2.select", "", "lbracket");
string_setting Input::Joypad2::start (config(), "input.joypad2.start", "", "rbracket");
string_setting Input::GUI::load (config(), "input.gui.load", "", "none");
string_setting Input::GUI::pause (config(), "input.gui.pause", "", "f12");
string_setting Input::GUI::reset (config(), "input.gui.reset", "", "none");
string_setting Input::GUI::power (config(), "input.gui.power", "", "none");
string_setting Input::GUI::toggle_fullscreen(config(), "input.gui.toggle_fullscreen", "", "f11");
string_setting Input::GUI::toggle_menubar (config(), "input.gui.toggle_menubar", "", "escape");
string_setting Input::GUI::toggle_statusbar (config(), "input.gui.toggle_statusbar", "", "escape");
string_setting Input::GUI::load (config(), "input.gui.load", "", "none");
string_setting Input::GUI::pause (config(), "input.gui.pause", "", "f12");
string_setting Input::GUI::reset (config(), "input.gui.reset", "", "none");
string_setting Input::GUI::power (config(), "input.gui.power", "", "none");
string_setting Input::GUI::quit (config(), "input.gui.quit", "", "none");
string_setting Input::GUI::speed_decrease (config(), "input.gui.speed_decrease", "", "divide");
string_setting Input::GUI::speed_increase (config(), "input.gui.speed_increase", "", "multiply");
string_setting Input::GUI::frameskip_decrease(config(), "input.gui.frameskip_decrease", "", "subtract");
string_setting Input::GUI::frameskip_increase(config(), "input.gui.frameskip_increase", "", "add");
string_setting Input::GUI::toggle_fullscreen (config(), "input.gui.toggle_fullscreen", "", "f11");
string_setting Input::GUI::toggle_menubar (config(), "input.gui.toggle_menubar", "", "escape");
string_setting Input::GUI::toggle_statusbar (config(), "input.gui.toggle_statusbar", "", "escape");
struct Misc {
static integral_setting opacity;
@@ -187,4 +198,11 @@ string_setting Misc::status_text(config(), "misc.status_text",
"%f = executed frames per second\n"
"%m = maximum frames per second"
"", "%n : %f / %m");
};
struct Advanced {
static integral_setting enable;
} advanced;
integral_setting Advanced::enable(config(), "advanced.enable", "Enable advanced, developer-oriented UI options", integral_setting::boolean, false);
} //namespace config

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