diff --git a/bsnes/data/cheats.xml b/bsnes/data/cheats.xml
index 949d894e..b49542f4 100755
--- a/bsnes/data/cheats.xml
+++ b/bsnes/data/cheats.xml
@@ -1673,6 +1673,10 @@
Have Fezi-copter
+ 6DAC-6FDD
+
+
+ Have Fezi-copter (alt)
7E0064FF
@@ -3535,7 +3539,6 @@
Invincibility
2D87-AD04
- EDA6-AFDD
Infinite lives
@@ -5042,6 +5045,10 @@
BioMetal (USA)
+
+ Invincibility (blinking)
+ 406D-DDD2
+
Infinite lives
C26E-6D02
@@ -9409,6 +9416,14 @@
Cutthroat Island (USA)
+
+ Stage select menu after character select screen
+ 3C6B-479E
+
+
+ Stage select menu after character select screen (alt)
+ 878C9DEA
+
Infinite health - P1
7E09F428
@@ -17330,6 +17345,18 @@
Infinite time
A2C0-A7D0
+
+ Hit anywhere
+ 3CA4-0FD0
+ 40AD-04A0
+ 7DA4-0F00
+ 89A4-0D60
+ F9A4-0DA0
+
+
+ Enemies never get knocked down, attack until they die
+ 7E0D7000
+
Slower timer
D4C9-AFD0
@@ -17338,10 +17365,6 @@
Faster timer
DDC9-AFD0
-
- Enemies never get knocked down, hit them until they die
- 7E0D7000
-
Enemy 1 has no health
7E101400
@@ -24315,6 +24338,19 @@
Infinite Arrows
17E5-22E6
+
+ Hit anywhere (disable before fighting Ganon, use the Boomerang instead of Sword to hit switches)
+ 40E2-6D96
+ 6D3E-A7FC
+ 403F-DD28
+ 40EC-AF26
+ 6D34-D7F8
+ 4068-A0E6
+
+
+ Get items from anywhere
+ 402F-07B6
+
Always get Faerie at the Pond Of Happiness (as if you threw in 100 rupees)
7EF36A64
@@ -24336,7 +24372,7 @@
DDB5-049E
- Enemies that normally drop items will drop them 100% of the time
+ 100% enemy drop rate (from enemies that normally drop items)
DDE8-142C
@@ -30756,6 +30792,10 @@
One hit kills
40DE-7FD2
+
+ Hit anywhere
+ 6DD8-7DD2
+
Multi-jump
1DFC-E400
@@ -30805,6 +30845,10 @@
One hit kills (most enemies)
6DB5-CD97
+
+ Hit anywhere
+ 40B1-34F4
+
Immune to drain attack
C2AD-4401
@@ -30890,10 +30934,6 @@
Infinite lives (alt)
7E1F8009
-
- Start with all weapons and all enemies defeated (except Sigma)
- 23BD-3F07
-
Infinite weapons once obtained
C9B3-4769
@@ -30902,6 +30942,10 @@
One hit kills (most enemies)
6DB5-CD97
+
+ Hit anywhere
+ 40B1-34F4
+
Have all equipment
7E1F99FF
@@ -30944,6 +30988,10 @@
Weapon charges to 1st power level faster
DDB1-4F61
+
+ Start with all weapons and all enemies defeated (except Sigma)
+ 23BD-3F07
+
Start with less health
D6BE-47AF
@@ -31063,6 +31111,12 @@
Have sub-tank 4 full
7E1FB9FF
+
+ Hit anywhere
+ 4028-A73F
+ C222-6734
+ D4E7-DDFB
+
One hit kills
6D2D-AF14
@@ -31084,10 +31138,6 @@
Infinite health
C2AD-6FF7
-
- Start with max health bar
- F02A-ADF4
-
Infinite lives
7E1FB409
@@ -31108,14 +31158,14 @@
82CB-0D2F
82CA-0F2F
-
- Always Super Shot
- 7E0A6702
-
Infinite Air Dash
7E0A3478
+
+ Always have Super Shot
+ 7E0A6702
+
Have Zero-Saber
7E1FB2FC
@@ -31129,8 +31179,10 @@
7E0CF801
- Skip bosses at start of game and proceed to stage select
- B933-DF6C
+ Hit anywhere
+ 40AC-A7B4
+ 6DA0-ADF7
+ 6DAF-AD97
Multi-jump
@@ -31150,6 +31202,14 @@
Ultra mega-jump
D886-6F26
+
+ Skip bosses at start of game and proceed to stage select
+ B933-DF6C
+
+
+ Start with max health bar
+ F02A-ADF4
+
Metal Combat - Falcon's Revenge (USA)
@@ -31984,6 +32044,13 @@
First strike of any kind wins round
DDBC-370F
+
+ Hit anywhere - P1
+ 3DBF-3D0F
+ 27BF-3D6F
+ F6BF-3DAF
+ 74BF-3F0F
+
All throws do more damage
56B9-4DAD
@@ -32507,13 +32574,37 @@
C239-CD62
- First round / one button fatalities
+ First round and one button fatalities
7E3AF001
Infinite continues
A220-3FB6
+
+ P1 takes all damage
+ DD37-CF62
+
+
+ P2 takes all damage
+ 6D37-CF02
+
+
+ Hit anywhere - P1
+ 0AE6-3F0E
+ 0AE6-340E
+ 0AE6-34DE
+ 39E6-346E
+ 39E6-3FAE
+ 3DE6-3DDE
+ 6D30-1462
+ C4E6-3F6E
+ D4E6-3D0E
+ DDE6-3D6E
+ EDE6-3DAE
+ D7E6-3FDE
+ EE30-14A2
+
Press A on main menu for Sound Test
D42E-44D8
@@ -32530,14 +32621,6 @@
Press X on main menu for Scott's Menu
D42B-1FD8
-
- P1 takes all damage
- DD37-CF62
-
-
- P2 takes all damage
- 6D37-CF02
-
Always fight Kano
CE8F-3FB7
@@ -32710,6 +32793,10 @@
Infinite time
6DC7-1DAA
+
+ Infinite continues
+ C2C4-47AA
+
No health - P1
DDB1-1FF7
@@ -32719,12 +32806,15 @@
DDB5-1FF7
- Have 127x more fatality time
- 5EC2-CF02
+ Hit anywhere - P1
+ 0DB0-4F97
+ 2DB0-4FF7
+ 3DB0-4D97
+ DDB0-4DB7
- Infinite continues
- C2C4-47AA
+ Have 127x more fatality time
+ 5EC2-CF02
Disable throws - 2P mode
@@ -44004,6 +44094,13 @@
DD80-7FAD
D580-74DD
+
+ Hit anywhere (except projectiles) - P1
+ 3DC7-8D0D
+ 6DC7-8D6D
+ BDC7-8FDD
+ DBC7-8DAD
+
Street Fighter II (USA)
@@ -44017,6 +44114,13 @@
Win 1 bout to win the match instead of 2 out of 3 (disable before fighting M. Bison)
DF80-AD64
+
+ Hit anywhere (except projectiles) - P1
+ 3D29-A4A7
+ 8D29-A767
+ DD29-A7D7
+ D329-A707
+
Dizziness wears off very quickly
EDBE-0F09
@@ -44389,6 +44493,13 @@
Infinite time (alt)
7E18F399
+
+ Hit anywhere (except projectiles) - P1
+ 3D98-8704
+ 8D9A-8DD4
+ DD98-8764
+ D598-87A4
+
Select same character - both players
7E184820
@@ -46655,19 +46766,19 @@
Super Double Dragon (USA)
- Invincibility
- C267-0DD6
-
-
- Infinite health
+ Invincibility - both players
1D6F-0766
- Infinite lives
- C286-6F05
+ Invincibility - P1
+ C267-0DD6
Infinite lives - P1
+ C286-6F05
+
+
+ Infinite lives - P1 (alt)
4A86-6F05
@@ -46706,6 +46817,30 @@
1 life - 2P game A
DF88-0D6B
+
+ Start on Mission 2 (enable on Mode Seclect screen, then disable)
+ 7E001C14
+
+
+ Start on Mission 3 (enable on Mode Seclect screen, then disable)
+ 7E001C17
+
+
+ Start on Mission 4 (enable on Mode Seclect screen, then disable)
+ 7E001C1C
+
+
+ Start on Mission 5 (enable on Mode Seclect screen, then disable)
+ 7E001C1D
+
+
+ Start on Mission 6 (enable on Mode Seclect screen, then disable)
+ 7E001C1F
+
+
+ Start on Mission 7 (enable on Mode Seclect screen, then disable)
+ 7E001C20
+
Super Ghouls'n Ghosts (USA)
@@ -46896,6 +47031,11 @@
Super Mario All-Stars (USA)
(SMB) Invincibility
+ 62E7-A7D2
+ 2DE7-A7A2
+
+
+ (SMB) Invincibility (Starman effect)
292B-67DE
@@ -46923,16 +47063,27 @@
6D84-DF03
- (SMB) Play as Big Mario
- 7E07AE05
-
-
- (SMB) Play as Fire Mario
- 23C2BB03
+ (SMB) Always Fiery Mario after first hit
+ CB29-AF0E
+ D429-AF6E
+ CB8B-676A
+ DD8B-67AA
(SMB) Multi-jump
- 23C2BB02
+ 2D8E-D7D2
+
+
+ (SMB) Fireballs hit anywhere
+ 4028-D4DE
+
+
+ (SMB) Fireballs can kill Bullet Bill
+ 4025-07AE
+
+
+ (SMB) Fireballs can kill Buzzy Beetle
+ 6D2E-DD6E
(SMB) Run without holding the dash button
@@ -47022,13 +47173,21 @@
7E00853B
- (SMB2) Always big
+ (SMB2) Infinite hearts
+ DD32-6966
+
+
+ (SMB2) Always big Mario
7E04C31F
- (SMB2) Always small
+ (SMB2) Always small Mario
7E04C30F
+
+ (SMB2) Infinite lives
+ C26E-D5A6
+
(SMB2) Multi-jump - all characters
D966-6166
@@ -47061,10 +47220,6 @@
(SMB2) 99 lives after continue
1761-05D0
-
- (SMB2) Infinite lives
- C26E-D5A6
-
(SMB2) Continue with 3 hearts instead of 2
DF6B-A9A1
@@ -47073,10 +47228,6 @@
(SMB2) Continue with 4 hearts
D46B-A9A1
-
- (SMB2) Never lose hearts
- DD32-6966
-
(SMB2) Jumping in place charges super jump
7A60-A966
@@ -47097,38 +47248,55 @@
(SMB3) Invincibility (Starman)
7E0553FF
+
+ (SMB3) Infinite lives
+ 82BB-0C6D
+
(SMB3) Infinite time
6D3D-6619
- (SMB3) Play as Small Mario
+ (SMB3) Always Small Mario
7E00BB00
- (SMB3) Play as Big Mario
+ (SMB3) Always Big Mario
7E00BB01
- (SMB3) Play as Fire Mario
+ (SMB3) Always Fire Mario
7E00BB02
- (SMB3) Play as Raccoon Mario
+ (SMB3) Always Raccoon Mario
7E00BB03
- (SMB3) Play as Frog Mario
+ (SMB3) Always Frog Mario
7E00BB04
- (SMB3) Play as Tanooki Mario
+ (SMB3) Always Tanooki Mario
7E00BB05
- (SMB3) Play as Hammer Bros. Mario
+ (SMB3) Always Hammer Bros. Mario
7E00BB06
+
+ (SMB3) Fireballs hit anywhere
+ 4083-D8F3
+ 408D-08F3
+
+
+ (SMB3) Tail hits anywhere
+ 40C4-6C22
+
+
+ (SMB3) Fireballs can kill most enemies
+ 4084-0BB3
+
(SMB3) Have Magic Whistle
7E1D800C
@@ -47146,7 +47314,7 @@
DDAF-A8A3
- (SMB3) Fly for an unlimited amount of time
+ (SMB3) Infinite flying time
EEA4-AB63
@@ -47216,10 +47384,6 @@
(SMB3) After getting star, invincible until end of level (may have to disable to jump)
C23B-680D
-
- (SMB3) Infinite lives
- 82BB-0C6D
-
(SMB3) 1 life after continue
DFBB-DBAF
@@ -47289,13 +47453,13 @@
Super Mario All-Stars + Super Mario World (USA)
(SMB) Invincibility
- 292B-67DE
-
-
- (SMB) Invincibility (alt)
62E7-A7D2
2DE7-A7A2
+
+ (SMB) Invincibility (Starman effect)
+ 292B-67DE
+
(SMB) Invincibility (Starman)
7E07AF0F
@@ -47305,21 +47469,28 @@
7E075A05
- (SMB) Play as Big Mario
- 7E07AE05
-
-
- (SMB) Play as Big Mario (alt)
- 23C2BB02
-
-
- (SMB) Play as Fire Mario
- 23C2BB03
+ (SMB) Always Fiery Mario after first hit
+ CB29-AF0E
+ D429-AF6E
+ CB8B-676A
+ DD8B-67AA
(SMB) Multi-jump
2D8E-D7D2
+
+ (SMB) Fireballs hit anywhere
+ 4028-D4DE
+
+
+ (SMB) Fireballs can kill Bullet Bill
+ 4025-07AE
+
+
+ (SMB) Fireballs can kill Buzzy Beetle
+ 6D2E-DD6E
+
(SMB) Run without holding the dash button
DD8E-D702
@@ -47341,17 +47512,9 @@
C26E-D5A6
- (SMB2) Never lose hearts
+ (SMB2) Infinite hearts
DD32-6966
-
- (SMB2) Always Big
- 7E04C31F
-
-
- (SMB2) Always Small
- 7E04C30F
-
(SMB2) Multi-jump - all characters
D966-6166
@@ -47381,33 +47544,37 @@
7E0553FF
- (SMB3) Play as Small Mario
+ (SMB3) Always Small Mario
7E00BB00
- (SMB3) Play as Big Mario
+ (SMB3) Always Big Mario
7E00BB01
- (SMB3) Play as Fire Mario
+ (SMB3) Always Fiery Mario
7E00BB02
- (SMB3) Play as Raccoon Mario
+ (SMB3) Always Raccoon Mario
7E00BB03
- (SMB3) Play as Frog Mario
+ (SMB3) Always Frog Mario
7E00BB04
- (SMB3) Play as Tanooki Mario
+ (SMB3) Always Tanooki Mario
7E00BB05
- (SMB3) Play as Hammer Bros Mario
+ (SMB3) Always Hammer Bros Mario
7E00BB06
+
+ (SMB3) Infinite flying time
+ 23CB26FF
+
(SMB3) Have Magic Whistle
7E1D800C
@@ -47417,12 +47584,17 @@
7E056EFF
- (SMB3) Fly at anytime (run meter always full)
- 23CB1F00
+ (SMB3) Fireballs hit anywhere
+ 4083-D8F3
+ 408D-08F3
- (SMB3) Fly for an unlimited amount of time
- 23CB26FF
+ (SMB3) Tail hits anywhere
+ 40C4-6C22
+
+
+ (SMB3) Fireballs can kill most enemies
+ 4084-0BB3
(SMW) Invincibility
@@ -47445,9 +47617,13 @@
7E001902
- (SMW) Always Fire Mario
+ (SMW) Always Fiery Mario
7E001903
+
+ (SMW) Always have Yoshi
+ 7E0DC101
+
(SMW) Infinite time
7E0F3109
@@ -47458,10 +47634,6 @@
(SMW) Infinite P-Balloon time
7E1891FF
-
- (SMW) Always have Yoshi
- 7E0DC101
-
(SMW) Infinite flying time for Yoshi
C2EC-0700
@@ -47892,6 +48064,10 @@
89E4-AFD9
89C6-D4DB
+
+ Infinite lives
+ C222-D4DD
+
Infinite flying time for Yoshi
C2EC-0700
@@ -47905,8 +48081,24 @@
7E1891FF
- Infinite lives
- C222-D4DD
+ Always Small Mario
+ 7E001900
+
+
+ Always Big Mario
+ 7E001901
+
+
+ Always Cape Mario
+ 7E001902
+
+
+ Always Fiery Mario
+ 7E001903
+
+
+ Always have Yoshi
+ 7E0DC101
Multi-jump
@@ -47921,6 +48113,31 @@
F53F-6767
DD3F-67A7
+
+ Cape hit anywhere
+ 40BE-AD66
+
+
+ Fireballs hits anywhere
+ 40C2-D7A6
+
+
+ Fireballs shoot straight
+ DDEA-6F07
+ DDB2-AFD8
+
+
+ Fireballs turn most enemies into Flowers
+ 59C4-0466
+
+
+ Fireballs turn most enemies into 1-Up Mushrooms
+ 56C4-0466
+
+
+ Fireballs turn most enemies into Starmen
+ 51C4-0466
+
Low-jump
D02C-AF6F
@@ -47933,26 +48150,6 @@
Mega-jump
DF2C-AF6F
-
- Always Small Mario
- 7E001900
-
-
- Always Big Mario
- 7E001901
-
-
- Always Cape Mario
- 7E001902
-
-
- Always Fire Mario
- 7E001903
-
-
- Always have Yoshi
- 7E0DC101
-
Little Yoshi grows after eating 1 enemy instead of 5
DFCE-64A0
@@ -47969,11 +48166,6 @@
Little Yoshi grows after eating 4 enemies
D0CE-64A0
-
- Shoot fireballs straight
- DDEA-6F07
- DDB2-AFD8
-
Activate green blocks (disable before entering the Green Switch Palace)
7E1F2701
@@ -48477,6 +48669,11 @@
Super-jumps don't drain energy
C22A-456D
+
+ Enemies die on contact (Speed Booster effect)
+ 6DC8-4CDF
+ 6DCC-4BDF
+
Kill most enemies on contact (prevents bomb-bouncing)
7E0A6E0F
@@ -50434,6 +50631,13 @@
Instant win - P1
7E0771FF
+
+ Hit anywhere (except projectiles) - P1
+ 3D1D-5DDF
+ 8D1D-5DAF
+ 0D1D-5D0F
+ D51D-5D6F
+
No charging required for some special moves
D002-EDD5
@@ -54788,13 +54992,29 @@
7D7B-FE7C
- First round / one button fatalities
+ First round and one button fatalities
7E3BE301
Max fatality time
DF73-2A7C
+
+ Hit anywhere - P1
+ 0AEB-3F97
+ 0AEB-34F7
+ 31EB-34B7
+ 35EB-3F27
+ 3DEB-3DF7
+ 46EB-3FB7
+ 84EB-3497
+ BD3C-C49F
+ D4EB-3D97
+ DDEB-3DB7
+ D7EB-3FF7
+ EDEB-3D27
+ EE3C-C4BF
+
Blank versus screen
EE37-CF02
@@ -55467,6 +55687,21 @@
7E1B8963
+
+ Ushio to Tora (Japan)
+
+ Invincibility
+ 7E022226
+
+
+ Infinite health
+ 7E021E40
+
+
+ Infinite lives
+ 7E060863
+
+
Utopia - The Creation of a Nation (USA)
@@ -57692,15 +57927,15 @@
- Zool - Ninja of the Nth Dimension (USA)
+ Zool - Ninja of the 'Nth' Dimension (USA)
+
+ Invincibility
+ 7E05DCFF
+
Invincibility (blinking)
7E1D8B49
-
- Invincibility (not blinking)
- 7E05DCFF
-
Infinite health
7E1CF1FA
diff --git a/bsnes/nall/directory.hpp b/bsnes/nall/directory.hpp
index c4f94c9a..4d3bcba5 100755
--- a/bsnes/nall/directory.hpp
+++ b/bsnes/nall/directory.hpp
@@ -42,20 +42,21 @@ struct directory {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
- if(wildcard(name, pattern)) list.append(string(name, "/"));
+ if(wildcard(name, pattern)) list.append(name);
}
}
while(FindNextFile(handle, &data) != false) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
- if(wildcard(name, pattern)) list.append(string(name, "/"));
+ if(wildcard(name, pattern)) list.append(name);
}
}
}
FindClose(handle);
}
if(list.size() > 0) sort(&list[0], list.size());
+ foreach(name, list) name.append("/"); //must append after sorting
return list;
}
@@ -109,14 +110,14 @@ struct directory {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if(ep->d_type & DT_DIR) {
- if(wildcard(ep->d_name, pattern)) list.append(string(ep->d_name, "/"));
+ if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
}
}
closedir(dp);
}
if(list.size() > 0) sort(&list[0], list.size());
+ foreach(name, list) name.append("/"); //must append after sorting
return list;
-
}
inline lstring directory::files(const string &pathname, const string &pattern) {
diff --git a/bsnes/nall/file.hpp b/bsnes/nall/file.hpp
index 103c7d4a..8c4ef894 100755
--- a/bsnes/nall/file.hpp
+++ b/bsnes/nall/file.hpp
@@ -1,15 +1,7 @@
#ifndef NALL_FILE_HPP
#define NALL_FILE_HPP
-#include
-#include
-
-#if !defined(_WIN32)
- #include
-#else
- #include
-#endif
-
+#include
#include
#include
#include
@@ -28,6 +20,7 @@ namespace nall {
public:
enum class mode : unsigned { read, write, readwrite, writeread };
enum class index : unsigned { absolute, relative };
+ enum class time : unsigned { create, modify, access };
uint8_t read() {
if(!fp) return 0xff; //file not open
@@ -142,52 +135,60 @@ namespace nall {
return file_offset >= file_size;
}
- static bool exists(const char *fn) {
+ static bool exists(const char *filename) {
#if !defined(_WIN32)
- FILE *fp = fopen(fn, "rb");
+ struct stat64 data;
+ return stat64(filename, &data) == 0;
#else
- FILE *fp = _wfopen(utf16_t(fn), L"rb");
+ struct __stat64 data;
+ return _wstat64(utf16_t(filename), &data) == 0;
#endif
- if(fp) {
- fclose(fp);
- return true;
- }
- return false;
}
- static unsigned size(const char *fn) {
+ static uintmax_t size(const char *filename) {
#if !defined(_WIN32)
- FILE *fp = fopen(fn, "rb");
+ struct stat64 data;
+ stat64(filename, &data);
#else
- FILE *fp = _wfopen(utf16_t(fn), L"rb");
+ struct __stat64 data;
+ _wstat64(utf16_t(filename), &data);
#endif
- unsigned filesize = 0;
- if(fp) {
- fseek(fp, 0, SEEK_END);
- filesize = ftell(fp);
- fclose(fp);
+ return S_ISREG(data.st_mode) ? data.st_size : 0u;
+ }
+
+ static time_t timestamp(const char *filename, file::time mode = file::time::create) {
+ #if !defined(_WIN32)
+ struct stat64 data;
+ stat64(filename, &data);
+ #else
+ struct __stat64 data;
+ _wstat64(utf16_t(filename), &data);
+ #endif
+ switch(mode) { default:
+ case file::time::create: return data.st_ctime;
+ case file::time::modify: return data.st_mtime;
+ case file::time::access: return data.st_atime;
}
- return filesize;
}
bool open() {
return fp;
}
- bool open(const char *fn, mode mode_) {
+ bool open(const char *filename, mode mode_) {
if(fp) return false;
switch(file_mode = mode_) {
#if !defined(_WIN32)
- case mode::read: fp = fopen(fn, "rb"); break;
- case mode::write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
- case mode::readwrite: fp = fopen(fn, "rb+"); break;
- case mode::writeread: fp = fopen(fn, "wb+"); break;
+ case mode::read: fp = fopen(filename, "rb" ); break;
+ case mode::write: fp = fopen(filename, "wb+"); break; //need read permission for buffering
+ case mode::readwrite: fp = fopen(filename, "rb+"); break;
+ case mode::writeread: fp = fopen(filename, "wb+"); break;
#else
- case mode::read: fp = _wfopen(utf16_t(fn), L"rb"); break;
- case mode::write: fp = _wfopen(utf16_t(fn), L"wb+"); break;
- case mode::readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break;
- case mode::writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break;
+ case mode::read: fp = _wfopen(utf16_t(filename), L"rb" ); break;
+ case mode::write: fp = _wfopen(utf16_t(filename), L"wb+"); break;
+ case mode::readwrite: fp = _wfopen(utf16_t(filename), L"rb+"); break;
+ case mode::writeread: fp = _wfopen(utf16_t(filename), L"wb+"); break;
#endif
}
if(!fp) return false;
diff --git a/bsnes/nall/platform.hpp b/bsnes/nall/platform.hpp
index 72eeec09..a7314493 100755
--- a/bsnes/nall/platform.hpp
+++ b/bsnes/nall/platform.hpp
@@ -1,6 +1,12 @@
#ifndef NALL_PLATFORM_HPP
#define NALL_PLATFORM_HPP
+#if defined(_WIN32)
+ //minimum version needed for _wstat64, etc
+ #undef __MSVCRT_VERSION__
+ #define __MSVCRT_VERSION__ 0x0601
+#endif
+
#include
//=========================
@@ -18,16 +24,19 @@
#include
#include
+#include
+#include
+
#if defined(_WIN32)
#include
#include
#include
+ #include
#undef interface
#define dllexport __declspec(dllexport)
#else
#include
#include
- #include
#define dllexport
#endif
@@ -53,11 +62,11 @@
#if defined(_WIN32)
#define getcwd _getcwd
#define ftruncate _chsize
- #define putenv _putenv
#define mkdir(n, m) _wmkdir(nall::utf16_t(n))
+ #define putenv _putenv
#define rmdir _rmdir
- #define vsnprintf _vsnprintf
#define usleep(n) Sleep(n / 1000)
+ #define vsnprintf _vsnprintf
#endif
//================
diff --git a/bsnes/nall/string/cast.hpp b/bsnes/nall/string/cast.hpp
index 14f005da..9498392c 100755
--- a/bsnes/nall/string/cast.hpp
+++ b/bsnes/nall/string/cast.hpp
@@ -6,8 +6,10 @@ namespace nall {
//this is needed, as C++0x does not support explicit template specialization inside classes
template<> inline const char* to_string (bool v) { return v ? "true" : "false"; }
template<> inline const char* to_string (signed int v) { static char temp[256]; snprintf(temp, 255, "%+d", v); return temp; }
-template<> inline const char* to_string (unsigned int v) { static char temp[256]; snprintf(temp, 255, "%u", v); return temp; }
-template<> inline const char* to_string (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
+template<> inline const char* to_string (unsigned int v) { static char temp[256]; snprintf(temp, 255, "%u", v); return temp; }
+template<> inline const char* to_string (intmax_t v) { static char temp[256]; snprintf(temp, 255, "%+lld", (long long)v); return temp; }
+template<> inline const char* to_string (uintmax_t v) { static char temp[256]; snprintf(temp, 255, "%llu", (unsigned long long)v); return temp; }
+template<> inline const char* to_string (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
template<> inline const char* to_string (char *v) { return v; }
template<> inline const char* to_string (const char *v) { return v; }
template<> inline const char* to_string (string v) { return v; }
diff --git a/bsnes/phoenix/core/core.cpp b/bsnes/phoenix/core/core.cpp
index ddb868cb..89d26718 100755
--- a/bsnes/phoenix/core/core.cpp
+++ b/bsnes/phoenix/core/core.cpp
@@ -34,6 +34,10 @@ void Font::setSize(unsigned size) { state.size = size; return p.setSize(size); }
void Font::setUnderline(bool underline) { state.underline = underline; return p.setUnderline(underline); }
Font::Font() : state(*new State), p(*new pFont(*this)) { p.constructor(); }
+void Timer::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); }
+void Timer::setInterval(unsigned milliseconds) { state.milliseconds = milliseconds; return p.setInterval(milliseconds); }
+Timer::Timer() : state(*new State), p(*new pTimer(*this)) { p.constructor(); }
+
MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::information(parent, text, buttons); }
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::question(parent, text, buttons); }
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::warning(parent, text, buttons); }
diff --git a/bsnes/phoenix/core/core.hpp b/bsnes/phoenix/core/core.hpp
index 2f087b42..f09e6a2c 100755
--- a/bsnes/phoenix/core/core.hpp
+++ b/bsnes/phoenix/core/core.hpp
@@ -6,6 +6,7 @@ struct Widget;
struct pOS;
struct pFont;
+struct pTimer;
struct pWindow;
struct pAction;
struct pMenu;
@@ -82,6 +83,18 @@ struct Font : Object {
pFont &p;
};
+struct Timer : Object {
+ nall::function onTimeout;
+
+ void setEnabled(bool enabled = true);
+ void setInterval(unsigned milliseconds);
+
+ Timer();
+ struct State;
+ State &state;
+ pTimer &p;
+};
+
struct MessageWindow : Object {
enum class Buttons : unsigned {
Ok,
diff --git a/bsnes/phoenix/core/layout/vertical-layout.cpp b/bsnes/phoenix/core/layout/vertical-layout.cpp
index e3185001..373c8249 100755
--- a/bsnes/phoenix/core/layout/vertical-layout.cpp
+++ b/bsnes/phoenix/core/layout/vertical-layout.cpp
@@ -69,10 +69,6 @@ Geometry VerticalLayout::minimumLayoutGeometry() {
return { 0, 0, maximumWidth ? MaximumSize : margin * 2 + width, maximumHeight ? MaximumSize : margin * 2 + height };
}
-void VerticalLayout::reset() {
- children.reset();
-}
-
void VerticalLayout::setGeometry(const Geometry &containerGeometry) {
auto children = this->children;
foreach(child, children) {
diff --git a/bsnes/phoenix/core/layout/vertical-layout.hpp b/bsnes/phoenix/core/layout/vertical-layout.hpp
index fb78247e..a280c269 100755
--- a/bsnes/phoenix/core/layout/vertical-layout.hpp
+++ b/bsnes/phoenix/core/layout/vertical-layout.hpp
@@ -5,7 +5,6 @@ struct VerticalLayout : public Layout {
void append(Widget &widget, unsigned width, unsigned height, unsigned spacing = 0);
Geometry minimumGeometry();
Geometry minimumLayoutGeometry();
- void reset();
void setGeometry(const Geometry &geometry);
void setMargin(unsigned margin);
void setParent(Window &parent);
diff --git a/bsnes/phoenix/core/state.hpp b/bsnes/phoenix/core/state.hpp
index a4d99bf7..75df5abb 100755
--- a/bsnes/phoenix/core/state.hpp
+++ b/bsnes/phoenix/core/state.hpp
@@ -13,6 +13,16 @@ struct Font::State {
}
};
+struct Timer::State {
+ bool enabled;
+ unsigned milliseconds;
+
+ State() {
+ enabled = false;
+ milliseconds = 0;
+ }
+};
+
struct Window::State {
bool backgroundColor;
unsigned backgroundColorRed, backgroundColorGreen, backgroundColorBlue;
diff --git a/bsnes/phoenix/gtk/gtk.cpp b/bsnes/phoenix/gtk/gtk.cpp
index c711d7a2..1c06df83 100755
--- a/bsnes/phoenix/gtk/gtk.cpp
+++ b/bsnes/phoenix/gtk/gtk.cpp
@@ -2,6 +2,7 @@
#include "settings.cpp"
#include "font.cpp"
+#include "timer.cpp"
#include "message-window.cpp"
#include "window.cpp"
@@ -31,10 +32,29 @@
Font pOS::defaultFont;
Geometry pOS::availableGeometry() {
- //TODO: is there a GTK+ function for this?
- //should return desktopGeometry() sans panels, toolbars, docks, etc.
- Geometry geometry = desktopGeometry();
- return { geometry.x + 64, geometry.y + 64, geometry.width - 128, geometry.height - 128 };
+ Display *display = XOpenDisplay(0);
+ int screen = DefaultScreen(display);
+
+ static Atom atom = X11None;
+ if(atom == X11None) atom = XInternAtom(display, "_NET_WORKAREA", True);
+
+ int format;
+ unsigned char *data = 0;
+ unsigned long items, after;
+ Atom returnAtom;
+
+ int result = XGetWindowProperty(
+ display, RootWindow(display, screen), atom, 0, 4, False, XA_CARDINAL, &returnAtom, &format, &items, &after, &data
+ );
+
+ XCloseDisplay(display);
+
+ if(result == Success && returnAtom == XA_CARDINAL && format == 32 && items == 4) {
+ unsigned long *workarea = (unsigned long*)data;
+ return { (signed)workarea[0], (signed)workarea[1], (unsigned)workarea[2], (unsigned)workarea[3] };
+ }
+
+ return desktopGeometry();
}
Geometry pOS::desktopGeometry() {
diff --git a/bsnes/phoenix/gtk/gtk.hpp b/bsnes/phoenix/gtk/gtk.hpp
index f6abacce..8a27fb03 100755
--- a/bsnes/phoenix/gtk/gtk.hpp
+++ b/bsnes/phoenix/gtk/gtk.hpp
@@ -57,6 +57,16 @@ struct pFont : public pObject {
void constructor();
};
+struct pTimer : public pObject {
+ Timer &timer;
+
+ void setEnabled(bool enabled);
+ void setInterval(unsigned milliseconds);
+
+ pTimer(Timer &timer) : timer(timer) {}
+ void constructor();
+};
+
struct pMessageWindow : public pObject {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);
diff --git a/bsnes/phoenix/gtk/timer.cpp b/bsnes/phoenix/gtk/timer.cpp
new file mode 100755
index 00000000..d04183f8
--- /dev/null
+++ b/bsnes/phoenix/gtk/timer.cpp
@@ -0,0 +1,24 @@
+static guint Timer_trigger(pTimer *self) {
+ //timer may have been disabled prior to triggering, so check state
+ if(self->timer.state.enabled) {
+ if(self->timer.onTimeout) self->timer.onTimeout();
+ }
+ //callback may have disabled timer, so check state again
+ if(self->timer.state.enabled) {
+ g_timeout_add(self->timer.state.milliseconds, (GSourceFunc)Timer_trigger, (gpointer)self);
+ }
+ //kill this timer instance (it is spawned above if needed again)
+ return false;
+}
+
+void pTimer::setEnabled(bool enabled) {
+ if(enabled) {
+ g_timeout_add(timer.state.milliseconds, (GSourceFunc)Timer_trigger, (gpointer)this);
+ }
+}
+
+void pTimer::setInterval(unsigned milliseconds) {
+}
+
+void pTimer::constructor() {
+}
diff --git a/bsnes/phoenix/phoenix.cpp b/bsnes/phoenix/phoenix.cpp
index 28307897..d73c3b6a 100755
--- a/bsnes/phoenix/phoenix.cpp
+++ b/bsnes/phoenix/phoenix.cpp
@@ -1,3 +1,6 @@
+#ifndef PHOENIX_CPP
+#define PHOENIX_CPP
+
#if defined(PHOENIX_WINDOWS)
#define UNICODE
#define WINVER 0x0501
@@ -14,13 +17,15 @@
#include
#include
#elif defined(PHOENIX_GTK)
- #define None X11None
+ #define None
#define Window X11Window
+ #define X11None 0L
#include
#include
#include
#include
+ #include
#undef None
#undef Window
@@ -35,3 +40,5 @@ using namespace nall;
namespace phoenix {
#include "core/core.cpp"
}
+
+#endif
diff --git a/bsnes/phoenix/phoenix.hpp b/bsnes/phoenix/phoenix.hpp
index aa0d94ab..bea075c1 100755
--- a/bsnes/phoenix/phoenix.hpp
+++ b/bsnes/phoenix/phoenix.hpp
@@ -1,3 +1,6 @@
+#ifndef PHOENIX_HPP
+#define PHOENIX_HPP
+
#include
#include
#include
@@ -11,3 +14,5 @@
namespace phoenix {
#include "core/core.hpp"
}
+
+#endif
diff --git a/bsnes/phoenix/qt/qt.cpp b/bsnes/phoenix/qt/qt.cpp
index d971d04b..42bd10ee 100755
--- a/bsnes/phoenix/qt/qt.cpp
+++ b/bsnes/phoenix/qt/qt.cpp
@@ -3,6 +3,7 @@
#include "settings.cpp"
#include "font.cpp"
+#include "timer.cpp"
#include "message-window.cpp"
#include "window.cpp"
diff --git a/bsnes/phoenix/qt/qt.moc b/bsnes/phoenix/qt/qt.moc
index 5f8602a4..dd08a286 100755
--- a/bsnes/phoenix/qt/qt.moc
+++ b/bsnes/phoenix/qt/qt.moc
@@ -1,7 +1,7 @@
/****************************************************************************
** Meta object code from reading C++ file 'qt.moc.hpp'
**
-** Created: Wed Mar 23 16:17:23 2011
+** Created: Tue May 24 19:33:16 2011
** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0)
**
** WARNING! All changes made in this file will be lost!
@@ -16,6 +16,67 @@
#endif
QT_BEGIN_MOC_NAMESPACE
+static const uint qt_meta_data_pTimer[] = {
+
+ // content:
+ 5, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 1, 14, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 0, // signalCount
+
+ // slots: signature, parameters, type, tag, flags
+ 8, 7, 7, 7, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_pTimer[] = {
+ "pTimer\0\0onTimeout()\0"
+};
+
+const QMetaObject pTimer::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_pTimer,
+ qt_meta_data_pTimer, 0 }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &pTimer::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *pTimer::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *pTimer::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_pTimer))
+ return static_cast(const_cast< pTimer*>(this));
+ if (!strcmp(_clname, "pObject"))
+ return static_cast< pObject*>(const_cast< pTimer*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int pTimer::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ switch (_id) {
+ case 0: onTimeout(); break;
+ default: ;
+ }
+ _id -= 1;
+ }
+ return _id;
+}
static const uint qt_meta_data_pWindow[] = {
// content:
diff --git a/bsnes/phoenix/qt/qt.moc.hpp b/bsnes/phoenix/qt/qt.moc.hpp
index d7466d6b..ba6ab2ad 100755
--- a/bsnes/phoenix/qt/qt.moc.hpp
+++ b/bsnes/phoenix/qt/qt.moc.hpp
@@ -56,6 +56,23 @@ struct pFont : public pObject {
void update();
};
+struct pTimer : public QObject, public pObject {
+ Q_OBJECT
+
+public:
+ Timer &timer;
+ QTimer *qtTimer;
+
+ void setEnabled(bool enabled);
+ void setInterval(unsigned milliseconds);
+
+ pTimer(Timer &timer) : timer(timer) {}
+ void constructor();
+
+public slots:
+ void onTimeout();
+};
+
struct pMessageWindow : public pObject {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);
diff --git a/bsnes/phoenix/qt/timer.cpp b/bsnes/phoenix/qt/timer.cpp
new file mode 100755
index 00000000..eba78b5a
--- /dev/null
+++ b/bsnes/phoenix/qt/timer.cpp
@@ -0,0 +1,21 @@
+void pTimer::setEnabled(bool enabled) {
+ if(enabled) {
+ qtTimer->start();
+ } else {
+ qtTimer->stop();
+ }
+}
+
+void pTimer::setInterval(unsigned milliseconds) {
+ qtTimer->setInterval(milliseconds);
+}
+
+void pTimer::constructor() {
+ qtTimer = new QTimer;
+ qtTimer->setInterval(0);
+ connect(qtTimer, SIGNAL(timeout()), SLOT(onTimeout()));
+}
+
+void pTimer::onTimeout() {
+ if(timer.onTimeout) timer.onTimeout();
+}
diff --git a/bsnes/phoenix/reference/font.cpp b/bsnes/phoenix/reference/font.cpp
index 9690c1d9..77d98f70 100755
--- a/bsnes/phoenix/reference/font.cpp
+++ b/bsnes/phoenix/reference/font.cpp
@@ -1,3 +1,7 @@
+Geometry pFont::geometry(const string &text) {
+ return { 0, 0, 0, 0 };
+}
+
void pFont::setBold(bool bold) {
}
diff --git a/bsnes/phoenix/reference/reference.cpp b/bsnes/phoenix/reference/reference.cpp
index a70254b6..d2b04b8e 100755
--- a/bsnes/phoenix/reference/reference.cpp
+++ b/bsnes/phoenix/reference/reference.cpp
@@ -1,6 +1,7 @@
#include "reference.hpp"
#include "font.cpp"
+#include "timer.cpp"
#include "message-window.cpp"
#include "window.cpp"
@@ -13,6 +14,7 @@
#include "widget/widget.cpp"
#include "widget/button.cpp"
+#include "widget/canvas.cpp"
#include "widget/check-box.cpp"
#include "widget/combo-box.cpp"
#include "widget/hex-edit.cpp"
diff --git a/bsnes/phoenix/reference/reference.hpp b/bsnes/phoenix/reference/reference.hpp
index 5f8ebf59..6c48b171 100755
--- a/bsnes/phoenix/reference/reference.hpp
+++ b/bsnes/phoenix/reference/reference.hpp
@@ -29,6 +29,7 @@ struct pOS : public pObject {
struct pFont : public pObject {
Font &font;
+ Geometry geometry(const string &text);
void setBold(bool bold);
void setFamily(const string &family);
void setItalic(bool italic);
@@ -39,6 +40,16 @@ struct pFont : public pObject {
void constructor();
};
+struct pTimer : public pObject {
+ Timer &timer;
+
+ void setEnabled(bool enabled);
+ void setInterval(unsigned milliseconds);
+
+ pTimer(Timer &timer) : timer(timer) {}
+ void constructor();
+};
+
struct pMessageWindow : public pObject {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);
@@ -136,6 +147,8 @@ struct pWidget : public pObject {
Widget &widget;
bool enabled();
+ Font& font();
+ Geometry minimumGeometry();
void setEnabled(bool enabled);
void setFocused();
void setFont(Font &font);
@@ -155,6 +168,16 @@ struct pButton : public pWidget {
void constructor();
};
+struct pCanvas : public pWidget {
+ Canvas &canvas;
+
+ uint32_t* buffer();
+ void update();
+
+ pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}
+ void constructor();
+};
+
struct pCheckBox : public pWidget {
CheckBox &checkBox;
diff --git a/bsnes/phoenix/reference/timer.cpp b/bsnes/phoenix/reference/timer.cpp
new file mode 100755
index 00000000..6cbe571a
--- /dev/null
+++ b/bsnes/phoenix/reference/timer.cpp
@@ -0,0 +1,8 @@
+void pTimer::setEnabled(bool enabled) {
+}
+
+void pTimer::setInterval(unsigned milliseconds) {
+}
+
+void pTimer::constructor() {
+}
diff --git a/bsnes/phoenix/reference/widget/canvas.cpp b/bsnes/phoenix/reference/widget/canvas.cpp
new file mode 100755
index 00000000..70295166
--- /dev/null
+++ b/bsnes/phoenix/reference/widget/canvas.cpp
@@ -0,0 +1,9 @@
+uint32_t* pCanvas::buffer() {
+ return 0;
+}
+
+void pCanvas::update() {
+}
+
+void pCanvas::constructor() {
+}
diff --git a/bsnes/phoenix/reference/widget/widget.cpp b/bsnes/phoenix/reference/widget/widget.cpp
index 40387671..a7787587 100755
--- a/bsnes/phoenix/reference/widget/widget.cpp
+++ b/bsnes/phoenix/reference/widget/widget.cpp
@@ -2,6 +2,14 @@ bool pWidget::enabled() {
return false;
}
+Font& pWidget::font() {
+ throw;
+}
+
+Geometry pWidget::minimumGeometry() {
+ return { 0, 0, 0, 0 };
+}
+
void pWidget::setEnabled(bool enabled) {
}
diff --git a/bsnes/phoenix/windows/timer.cpp b/bsnes/phoenix/windows/timer.cpp
new file mode 100755
index 00000000..8e2b3216
--- /dev/null
+++ b/bsnes/phoenix/windows/timer.cpp
@@ -0,0 +1,31 @@
+static linear_vector timers;
+
+static void CALLBACK Timer_timeoutProc(HWND hwnd, UINT msg, UINT_PTR timerID, DWORD time) {
+ foreach(timer, timers) {
+ if(timer->htimer == timerID) {
+ if(timer->timer.onTimeout) timer->timer.onTimeout();
+ return;
+ }
+ }
+}
+
+void pTimer::setEnabled(bool enabled) {
+ if(htimer) {
+ KillTimer(NULL, htimer);
+ htimer = 0;
+ }
+
+ if(enabled == true) {
+ htimer = SetTimer(NULL, 0U, timer.state.milliseconds, Timer_timeoutProc);
+ }
+}
+
+void pTimer::setInterval(unsigned milliseconds) {
+ //destroy and recreate timer if interval changed
+ setEnabled(timer.state.enabled);
+}
+
+void pTimer::constructor() {
+ timers.append(this);
+ htimer = 0;
+}
diff --git a/bsnes/phoenix/windows/window.cpp b/bsnes/phoenix/windows/window.cpp
index 1961b410..752bd0c1 100755
--- a/bsnes/phoenix/windows/window.cpp
+++ b/bsnes/phoenix/windows/window.cpp
@@ -36,8 +36,11 @@ Geometry pWindow::frameMargin() {
Geometry pWindow::geometry() {
Geometry margin = frameMargin();
- RECT rc;
- GetWindowRect(hwnd, &rc);
+
+ //note: GetWindowRect returns -32000(x),-32000(y) when window is minimized
+ WINDOWPLACEMENT wp;
+ GetWindowPlacement(hwnd, &wp);
+ RECT rc = wp.rcNormalPosition;
signed x = rc.left + margin.x;
signed y = rc.top + margin.y;
diff --git a/bsnes/phoenix/windows/windows.cpp b/bsnes/phoenix/windows/windows.cpp
index 4c3596a4..94b1497a 100755
--- a/bsnes/phoenix/windows/windows.cpp
+++ b/bsnes/phoenix/windows/windows.cpp
@@ -2,6 +2,7 @@
#include "object.cpp"
#include "font.cpp"
+#include "timer.cpp"
#include "message-window.cpp"
#include "window.cpp"
diff --git a/bsnes/phoenix/windows/windows.hpp b/bsnes/phoenix/windows/windows.hpp
index 70933131..76bace93 100755
--- a/bsnes/phoenix/windows/windows.hpp
+++ b/bsnes/phoenix/windows/windows.hpp
@@ -49,6 +49,17 @@ struct pFont : public pObject {
void constructor();
};
+struct pTimer : public pObject {
+ Timer &timer;
+ UINT_PTR htimer;
+
+ void setEnabled(bool enabled);
+ void setInterval(unsigned milliseconds);
+
+ pTimer(Timer &timer) : timer(timer) {}
+ void constructor();
+};
+
struct pMessageWindow : public pObject {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);
diff --git a/bsnes/snes/ppu/background/background.cpp b/bsnes/snes/ppu/background/background.cpp
index d654ceaf..cb3544cb 100755
--- a/bsnes/snes/ppu/background/background.cpp
+++ b/bsnes/snes/ppu/background/background.cpp
@@ -2,10 +2,16 @@
#include "mode7.cpp"
+//V = 0, H = 0
void PPU::Background::frame() {
}
+//H = 0
void PPU::Background::scanline() {
+}
+
+//H = 60
+void PPU::Background::begin() {
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
x = -7;
y = self.vcounter();
@@ -13,20 +19,26 @@ void PPU::Background::scanline() {
if(y == 1) {
mosaic.vcounter = regs.mosaic + 1;
mosaic.voffset = 1;
- mosaic.vscroll = regs.voffset;
- mosaic.hscroll = regs.hoffset;
+ cache.hoffset = regs.hoffset;
+ cache.voffset = regs.voffset;
} else if(--mosaic.vcounter == 0) {
mosaic.vcounter = regs.mosaic + 1;
mosaic.voffset += regs.mosaic + 1;
- mosaic.vscroll = regs.voffset;
- mosaic.hscroll = regs.hoffset;
+ cache.hoffset = regs.hoffset;
+ cache.voffset = regs.voffset;
}
- tile_counter = (7 - (mosaic.hscroll & 7)) << hires;
+ tile_counter = (7 - (cache.hoffset & 7)) << hires;
for(unsigned n = 0; n < 8; n++) data[n] = 0;
mosaic.hcounter = regs.mosaic + 1;
mosaic.hoffset = 0;
+
+ if(regs.mode == Mode::Mode7) return begin_mode7();
+ if(regs.mosaic == 0) {
+ cache.hoffset = regs.hoffset;
+ cache.voffset = regs.voffset;
+ }
}
void PPU::Background::get_tile() {
@@ -53,8 +65,8 @@ void PPU::Background::get_tile() {
unsigned px = x << hires;
unsigned py = (regs.mosaic == 0 ? y : mosaic.voffset);
- unsigned hscroll = mosaic.hscroll;
- unsigned vscroll = mosaic.vscroll;
+ unsigned hscroll = cache.hoffset;
+ unsigned vscroll = cache.voffset;
if(hires) {
hscroll <<= 1;
if(self.regs.interlace) py = (py << 1) + self.field();
@@ -67,8 +79,8 @@ void PPU::Background::get_tile() {
uint16 offset_x = (x + (hscroll & 7));
if(offset_x >= 8) {
- unsigned hval = self.bg3.get_tile((offset_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0);
- unsigned vval = self.bg3.get_tile((offset_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 8);
+ unsigned hval = self.bg3.get_tile((offset_x - 8) + (self.bg3.cache.hoffset & ~7), self.bg3.cache.voffset + 0);
+ unsigned vval = self.bg3.get_tile((offset_x - 8) + (self.bg3.cache.hoffset & ~7), self.bg3.cache.voffset + 8);
unsigned valid_mask = (id == ID::BG1 ? 0x2000 : 0x4000);
if(self.regs.bgmode == 4) {
@@ -205,6 +217,9 @@ void PPU::Background::reset() {
regs.hoffset = random(0x0000);
regs.voffset = random(0x0000);
+ cache.hoffset = 0;
+ cache.voffset = 0;
+
output.main.palette = 0;
output.main.priority = 0;
output.sub.palette = 0;
@@ -216,10 +231,8 @@ void PPU::Background::reset() {
mosaic.vcounter = 0;
mosaic.voffset = 0;
- mosaic.vscroll = 0;
mosaic.hcounter = 0;
mosaic.hoffset = 0;
- mosaic.hscroll = 0;
x = 0;
y = 0;
diff --git a/bsnes/snes/ppu/background/background.hpp b/bsnes/snes/ppu/background/background.hpp
index 86bd420d..26553af4 100755
--- a/bsnes/snes/ppu/background/background.hpp
+++ b/bsnes/snes/ppu/background/background.hpp
@@ -25,6 +25,11 @@ class Background {
uint16 voffset;
} regs;
+ struct Cache {
+ uint16 hoffset;
+ uint16 voffset;
+ } cache;
+
struct Output {
struct Pixel {
unsigned priority; //0 = none (transparent)
@@ -36,10 +41,8 @@ class Background {
struct Mosaic : Output::Pixel {
unsigned vcounter;
unsigned voffset;
- unsigned vscroll;
unsigned hcounter;
unsigned hoffset;
- unsigned hscroll;
} mosaic;
struct {
@@ -56,6 +59,7 @@ class Background {
void frame();
void scanline();
+ void begin();
void run(bool screen);
void reset();
@@ -63,6 +67,7 @@ class Background {
unsigned get_tile_color();
unsigned get_tile(unsigned x, unsigned y);
signed clip(signed n);
+ void begin_mode7();
void run_mode7();
void serialize(serializer&);
diff --git a/bsnes/snes/ppu/background/mode7.cpp b/bsnes/snes/ppu/background/mode7.cpp
index 8304f82e..bb630647 100755
--- a/bsnes/snes/ppu/background/mode7.cpp
+++ b/bsnes/snes/ppu/background/mode7.cpp
@@ -5,6 +5,12 @@ signed PPU::Background::clip(signed n) {
return n & 0x2000 ? (n | ~1023) : (n & 1023);
}
+//H = 60
+void PPU::Background::begin_mode7() {
+ cache.hoffset = self.regs.mode7_hoffset;
+ cache.voffset = self.regs.mode7_voffset;
+}
+
void PPU::Background::run_mode7() {
signed a = sclip<16>(self.regs.m7a);
signed b = sclip<16>(self.regs.m7b);
@@ -13,8 +19,8 @@ void PPU::Background::run_mode7() {
signed cx = sclip<13>(self.regs.m7x);
signed cy = sclip<13>(self.regs.m7y);
- signed hoffset = sclip<13>(self.regs.mode7_hoffset);
- signed voffset = sclip<13>(self.regs.mode7_voffset);
+ signed hoffset = sclip<13>(cache.hoffset);
+ signed voffset = sclip<13>(cache.voffset);
if(Background::x++ & ~255) return;
unsigned x = mosaic.hoffset;
diff --git a/bsnes/snes/ppu/ppu.cpp b/bsnes/snes/ppu/ppu.cpp
index b4a8de4c..f8a65e15 100755
--- a/bsnes/snes/ppu/ppu.cpp
+++ b/bsnes/snes/ppu/ppu.cpp
@@ -39,6 +39,10 @@ void PPU::enter() {
scanline();
add_clocks(60);
+ bg1.begin();
+ bg2.begin();
+ bg3.begin();
+ bg4.begin();
if(vcounter() <= 239) {
for(signed pixel = -7; pixel <= 255; pixel++) {
diff --git a/bsnes/snes/ppu/serialization.cpp b/bsnes/snes/ppu/serialization.cpp
index eaeb28d3..edf90f13 100755
--- a/bsnes/snes/ppu/serialization.cpp
+++ b/bsnes/snes/ppu/serialization.cpp
@@ -109,6 +109,9 @@ void PPU::Background::serialize(serializer &s) {
s.integer(regs.hoffset);
s.integer(regs.voffset);
+ s.integer(cache.hoffset);
+ s.integer(cache.voffset);
+
s.integer(output.main.priority);
s.integer(output.main.palette);
s.integer(output.main.tile);
@@ -126,10 +129,8 @@ void PPU::Background::serialize(serializer &s) {
s.integer(mosaic.vcounter);
s.integer(mosaic.voffset);
- s.integer(mosaic.vscroll);
s.integer(mosaic.hcounter);
s.integer(mosaic.hoffset);
- s.integer(mosaic.hscroll);
s.integer(tile_counter);
s.integer(tile);
diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp
index 113e28b0..9848141f 100755
--- a/bsnes/snes/snes.hpp
+++ b/bsnes/snes/snes.hpp
@@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
- static const char Version[] = "078.07";
+ static const char Version[] = "079";
static const unsigned SerializerVersion = 20;
}
}
diff --git a/snesfilter/2xSaI/2xSaI.cpp b/snesfilter/2xSaI/2xSaI.cpp
index 5f5a21f2..d9dc61fa 100755
--- a/snesfilter/2xSaI/2xSaI.cpp
+++ b/snesfilter/2xSaI/2xSaI.cpp
@@ -28,5 +28,5 @@ dllexport void filter_render(
}
}
- _2xSaI32((unsigned char*)temp, 1024, 0, (unsigned char*)output, outpitch, width, height);
+ _2xSaI32((unsigned char*)temp, width * sizeof(uint32_t), 0, (unsigned char*)output, outpitch, width, height);
}
diff --git a/snesfilter/2xSaI/Super-2xSaI.cpp b/snesfilter/2xSaI/Super-2xSaI.cpp
index eea01528..267e11e5 100755
--- a/snesfilter/2xSaI/Super-2xSaI.cpp
+++ b/snesfilter/2xSaI/Super-2xSaI.cpp
@@ -28,5 +28,5 @@ dllexport void filter_render(
}
}
- Super2xSaI32((unsigned char*)temp, 1024, 0, (unsigned char*)output, outpitch, width, height);
+ Super2xSaI32((unsigned char*)temp, width * sizeof(uint32_t), 0, (unsigned char*)output, outpitch, width, height);
}
diff --git a/snesfilter/2xSaI/Super-Eagle.cpp b/snesfilter/2xSaI/Super-Eagle.cpp
index 1e89de1f..c548348c 100755
--- a/snesfilter/2xSaI/Super-Eagle.cpp
+++ b/snesfilter/2xSaI/Super-Eagle.cpp
@@ -28,5 +28,5 @@ dllexport void filter_render(
}
}
- SuperEagle32((unsigned char*)temp, 1024, 0, (unsigned char*)output, outpitch, width, height);
+ SuperEagle32((unsigned char*)temp, width * sizeof(uint32_t), 0, (unsigned char*)output, outpitch, width, height);
}