summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNebuleon <nebuleon@alakazam>2014-07-19 07:20:17 +0000
committerNebuleon <nebuleon@alakazam>2014-07-19 07:20:17 +0000
commit5edc4b51b1d04393520ceb8649904ce2d6619398 (patch)
tree55d085c4330d4fbbeea2f34667ec9653dcdefdd4
parentff0993fce33b5f7810dcc51843cdd2ef56e92a3a (diff)
downloadReGBA-5edc4b51b1d04393520ceb8649904ce2d6619398.zip
ReGBA-5edc4b51b1d04393520ceb8649904ce2d6619398.tar.gz
ReGBA-5edc4b51b1d04393520ceb8649904ce2d6619398.tar.bz2
Support hardware-based scaling on the GCW Zero.
-rw-r--r--source/opendingux/data/manual-en.txt2
-rw-r--r--source/opendingux/data/manual-fr.txt2
-rw-r--r--source/opendingux/draw.c72
-rw-r--r--source/opendingux/draw.h7
-rw-r--r--source/opendingux/gui.c20
-rw-r--r--source/opendingux/main.c2
-rw-r--r--source/opendingux/od-input.c12
-rw-r--r--source/opendingux/port.c2
8 files changed, 101 insertions, 18 deletions
diff --git a/source/opendingux/data/manual-en.txt b/source/opendingux/data/manual-en.txt
index 7cf0ecb..6c97caf 100644
--- a/source/opendingux/data/manual-en.txt
+++ b/source/opendingux/data/manual-en.txt
@@ -41,7 +41,7 @@ In the Main Menu or any submenu containing options, you can press the Select key
- Display Settings -
> Boot from: "Cartridge ROM" does not show the GBA logo screen. "GBA BIOS" does. The GBA logo screen can be either 'Normmatt' in the Nintendo logo style, or the real GBA logo screen. See the 'Files' section for more information.
> FPS counter: "Show" displays rendered/emulated FPS at the bottom-left corner of the screen for performance testing purposes. "Hide" does not.
-> Image scaling: "None" shows the image exactly as a Game Boy Advance would (240x160), with a border around it. "Aspect" shows the image scaled up at the correct aspect ratio, with black bars (320x213). "Full" shows the image scaled up to the entire screen (320x240). The border in the unscaled mode can be the ReGBA Advanced SP border or a custom border. See the 'Files' section for more information.
+> Image scaling: "None" shows the image exactly as a Game Boy Advance would (240x160), with a border around it. "Aspect" shows the image scaled up at the correct aspect ratio, with black bars (320x213). "Full" shows the image scaled up to the entire screen (320x240). "Hardware" leaves scaling up to dedicated hardware on the GCW Zero. The border in the unscaled mode can be the ReGBA Advanced SP border or a custom border. See the 'Files' section for more information.
> Frame skipping: "Automatic" attempts to skip the least amount of frames necessary for the audio to be flawless. Manual selections exist up to 3 (~15 FPS). Most games are fine with automatic frame skipping.
> Fast-forward target: When fast-forwarding the game, this specifies the maximum speedup to allow, from 2x to 6x. If emulating a demanding game, the actual speedup may be less.
diff --git a/source/opendingux/data/manual-fr.txt b/source/opendingux/data/manual-fr.txt
index 11d6fd9..c4304b3 100644
--- a/source/opendingux/data/manual-fr.txt
+++ b/source/opendingux/data/manual-fr.txt
@@ -40,7 +40,7 @@ Dans le Menu Principal ou tout sous-menu comportant des options, vous pouvez app
- Réglages d'affichage (Display Settings) -
> Boot from: "Cartridge ROM" ne montre pas d'écran de démarrage. "GBA BIOS" le montre. L'écran de démarrage est soit 'Normmatt' dans le style du logo de Nintendo, ou bien l'écran de démarrage de la GBA. Voir la section 'Fichiers' pour plus d'informations.
> FPS counter: "Show" montre le nombre d'images rendues/émulées par seconde dans le coin inférieur gauche de l'écran afin de tester la performance de ReGBA. "Hide" ne montre pas ce compteur.
-> Image scaling: "None" montre l'image telle qu'une Game Boy Advance la montrerait (240x160) avec une bordure autour. "Aspect" montre l'image élargie proportionnellement avec des barres noires (320x213). "Full" montre l'image élargie pour remplir tout l'écran (320x240). La bordure pour le mode d'affichage original peut être soit la bordure ReGBA Advanced SP ou une bordure personnalisée. Voir la section 'Fichiers' pour plus d'informations.
+> Image scaling: "None" montre l'image telle qu'une Game Boy Advance la montrerait (240x160) avec une bordure autour. "Aspect" montre l'image élargie proportionnellement avec des barres noires (320x213). "Full" montre l'image élargie pour remplir tout l'écran (320x240). "Hardware" laisse le matériel dédié de la GCW Zero redimensionner l'image. La bordure pour le mode d'affichage original peut être soit la bordure ReGBA Advanced SP ou une bordure personnalisée. Voir la section 'Fichiers' pour plus d'informations.
> Frame skipping: "Automatic" tente de sauter le moins d'images possible tout en s'assurant que le rendu audio soit le meilleur possible. Des choix manuels existent jusqu'à 3 (~15 images par seconde). La plupart des jeux roulent bien avec le saut d'image automatique.
> Fast-forward target: Lorsque vous activez l'avance rapide, ceci spécifie le facteur d'accélération maximal. Si ReGBA émule un jeu exigeant, le facteur d'accélération peut être inférieur.
diff --git a/source/opendingux/draw.c b/source/opendingux/draw.c
index 32736c7..f8accf6 100644
--- a/source/opendingux/draw.c
+++ b/source/opendingux/draw.c
@@ -39,10 +39,6 @@ SDL_Surface *GBAScreenSurface = NULL;
SDL_Surface *OutputSurface = NULL;
SDL_Surface *BorderSurface = NULL;
-SDL_Rect ScreenRectangle = {
- 0, 0, GCW0_SCREEN_WIDTH, GCW0_SCREEN_HEIGHT
-};
-
video_scale_type PerGameScaleMode = 0;
video_scale_type ScaleMode = scaled_aspect;
@@ -68,6 +64,7 @@ void init_video()
// exit(1);
}
+ SDL_ShowCursor(SDL_DISABLE);
OutputSurface = SDL_SetVideoMode(GCW0_SCREEN_WIDTH, GCW0_SCREEN_HEIGHT, 16, SDL_HWSURFACE |
#ifdef SDL_TRIPLEBUF
SDL_TRIPLEBUF
@@ -82,8 +79,41 @@ void init_video()
0 /* alpha: none */);
GBAScreen = (uint16_t*) GBAScreenSurface->pixels;
+}
- SDL_ShowCursor(0);
+void SetMenuResolution()
+{
+#ifdef GCW_ZERO
+ if (SDL_MUSTLOCK(OutputSurface))
+ SDL_UnlockSurface(OutputSurface);
+ OutputSurface = SDL_SetVideoMode(GCW0_SCREEN_WIDTH, GCW0_SCREEN_HEIGHT, 16, SDL_HWSURFACE | SDL_DOUBLEBUF);
+ if (SDL_MUSTLOCK(OutputSurface))
+ SDL_LockSurface(OutputSurface);
+#endif
+}
+
+void SetGameResolution()
+{
+#ifdef GCW_ZERO
+ video_scale_type ResolvedScaleMode = ResolveSetting(ScaleMode, PerGameScaleMode);
+ unsigned int Width = GBA_SCREEN_WIDTH, Height = GBA_SCREEN_HEIGHT;
+ if (ResolvedScaleMode != hardware)
+ {
+ Width = GCW0_SCREEN_WIDTH;
+ Height = GCW0_SCREEN_HEIGHT;
+ }
+ if (SDL_MUSTLOCK(OutputSurface))
+ SDL_UnlockSurface(OutputSurface);
+ OutputSurface = SDL_SetVideoMode(Width, Height, 16, SDL_HWSURFACE |
+#ifdef SDL_TRIPLEBUF
+ SDL_TRIPLEBUF
+#else
+ SDL_DOUBLEBUF
+#endif
+ );
+ if (SDL_MUSTLOCK(OutputSurface))
+ SDL_LockSurface(OutputSurface);
+#endif
}
bool ApplyBorder(const char* Filename)
@@ -1340,6 +1370,26 @@ static inline void gba_render(uint16_t* Dest, uint16_t* Src,
}
}
+static inline void gba_convert(uint16_t* Dest, uint16_t* Src,
+ uint32_t SrcPitch, uint32_t DestPitch)
+{
+ uint32_t SrcSkip = SrcPitch - GBA_SCREEN_WIDTH * sizeof(uint16_t);
+ uint32_t DestSkip = DestPitch - GBA_SCREEN_WIDTH * sizeof(uint16_t);
+
+ uint32_t X, Y;
+ for (Y = 0; Y < GBA_SCREEN_HEIGHT; Y++)
+ {
+ for (X = 0; X < GBA_SCREEN_WIDTH * sizeof(uint16_t) / sizeof(uint32_t); X++)
+ {
+ *(uint32_t*) Dest = bgr555_to_rgb565(*(uint32_t*) Src);
+ Dest += 2;
+ Src += 2;
+ }
+ Src = (uint16_t*) ((uint8_t*) Src + SrcSkip);
+ Dest = (uint16_t*) ((uint8_t*) Dest + DestSkip);
+ }
+}
+
/* Downscales an image by half in width and in height; also does color
* conversion using the function above.
* Input:
@@ -1427,6 +1477,7 @@ void ApplyScaleMode(video_scale_type NewMode)
case fullscreen:
case fullscreen_subpixel:
case fullscreen_bilinear:
+ case hardware:
break;
}
}
@@ -1450,6 +1501,10 @@ void ReGBA_RenderScreen(void)
}
switch (ResolvedScaleMode)
{
+#ifndef GCW_ZERO
+ case hardware: /* Hardware, when there's no hardware to scale
+ images, acts as unscaled */
+#endif
case unscaled:
gba_render(OutputSurface->pixels, GBAScreen, GBAScreenSurface->pitch, OutputSurface->pitch);
break;
@@ -1486,6 +1541,11 @@ void ReGBA_RenderScreen(void)
(((GCW0_SCREEN_HEIGHT - (GBA_SCREEN_HEIGHT) * 4 / 3) / 2) * OutputSurface->pitch)) /* center vertically */,
GBAScreen, GBA_SCREEN_WIDTH, GBA_SCREEN_HEIGHT, GBAScreenSurface->pitch, OutputSurface->pitch);
break;
+
+#ifdef GCW_ZERO
+ case hardware:
+ gba_convert(OutputSurface->pixels, GBAScreen, GBAScreenSurface->pitch, OutputSurface->pitch);
+#endif
}
ReGBA_DisplayFPS();
@@ -1802,7 +1862,7 @@ static void ProgressUpdateInternal(uint32_t Current, uint32_t Total)
Line = "File action ongoing";
break;
}
- SDL_FillRect(OutputSurface, &ScreenRectangle, COLOR_PROGRESS_BACKGROUND);
+ SDL_FillRect(OutputSurface, NULL, COLOR_PROGRESS_BACKGROUND);
SDL_Rect TopLine = { (GCW0_SCREEN_WIDTH - PROGRESS_WIDTH) / 2, (GCW0_SCREEN_HEIGHT - PROGRESS_HEIGHT) / 2, PROGRESS_WIDTH, 1 };
SDL_FillRect(OutputSurface, &TopLine, COLOR_PROGRESS_OUTLINE);
diff --git a/source/opendingux/draw.h b/source/opendingux/draw.h
index c00d310..e5fe67d 100644
--- a/source/opendingux/draw.h
+++ b/source/opendingux/draw.h
@@ -9,8 +9,6 @@
extern SDL_Surface* GBAScreenSurface;
extern SDL_Surface* OutputSurface;
-extern SDL_Rect ScreenRectangle;
-
extern uint_fast8_t AudioFrameskip;
extern uint_fast8_t AudioFrameskipControl;
extern uint_fast8_t UserFrameskipControl;
@@ -33,6 +31,7 @@ typedef enum
scaled_aspect_subpixel,
fullscreen_subpixel,
unscaled,
+ hardware
} video_scale_type;
enum HorizontalAlignment {
@@ -80,6 +79,10 @@ extern uint32_t GetRenderedHeight(const char* str);
void ReGBA_VideoFlip();
+void SetMenuResolution();
+
+void SetGameResolution();
+
/*
* Returns a new allocation containing a copy of the GBA screen. Its pixels
* and lines are packed (the pitch is 480 bytes), and its pixel format is
diff --git a/source/opendingux/gui.c b/source/opendingux/gui.c
index 753b2fc..beffcdd 100644
--- a/source/opendingux/gui.c
+++ b/source/opendingux/gui.c
@@ -315,7 +315,11 @@ static void DefaultDisplayValueFunction(struct MenuEntry* DrawnMenuEntry, struct
static void DefaultDisplayBackgroundFunction(struct Menu* ActiveMenu)
{
- SDL_FillRect(OutputSurface, &ScreenRectangle, COLOR_BACKGROUND);
+ if (SDL_MUSTLOCK(OutputSurface))
+ SDL_UnlockSurface(OutputSurface);
+ SDL_FillRect(OutputSurface, NULL, COLOR_BACKGROUND);
+ if (SDL_MUSTLOCK(OutputSurface))
+ SDL_LockSurface(OutputSurface);
}
static void DefaultDisplayDataFunction(struct Menu* ActiveMenu, struct MenuEntry* ActiveMenuEntry)
@@ -509,7 +513,11 @@ static void DisplayHotkeyValue(struct MenuEntry* DrawnMenuEntry, struct MenuEntr
static void DisplayErrorBackgroundFunction(struct Menu* ActiveMenu)
{
- SDL_FillRect(OutputSurface, &ScreenRectangle, COLOR_ERROR_BACKGROUND);
+ if (SDL_MUSTLOCK(OutputSurface))
+ SDL_UnlockSurface(OutputSurface);
+ SDL_FillRect(OutputSurface, NULL, COLOR_ERROR_BACKGROUND);
+ if (SDL_MUSTLOCK(OutputSurface))
+ SDL_LockSurface(OutputSurface);
}
static void SavedStateMenuDisplayData(struct Menu* ActiveMenu, struct MenuEntry* ActiveMenuEntry)
@@ -1164,11 +1172,11 @@ static struct MenuEntry DisplayMenu_FPSCounter = {
static struct MenuEntry PerGameDisplayMenu_ScaleMode = {
ENTRY_OPTION("image_size", "Image scaling", &PerGameScaleMode),
- .ChoiceCount = 8, .Choices = { { "No override", "" }, { "Aspect, fast", "aspect" }, { "Full, fast", "fullscreen" }, { "Aspect, bilinear", "aspect_bilinear" }, { "Full, bilinear", "fullscreen_bilinear" }, { "Aspect, sub-pixel", "aspect_subpixel" }, { "Full, sub-pixel", "fullscreen_subpixel" }, { "None", "original" } }
+ .ChoiceCount = 9, .Choices = { { "No override", "" }, { "Aspect, fast", "aspect" }, { "Full, fast", "fullscreen" }, { "Aspect, bilinear", "aspect_bilinear" }, { "Full, bilinear", "fullscreen_bilinear" }, { "Aspect, sub-pixel", "aspect_subpixel" }, { "Full, sub-pixel", "fullscreen_subpixel" }, { "None", "original" }, { "Hardware", "hardware" } }
};
static struct MenuEntry DisplayMenu_ScaleMode = {
ENTRY_OPTION("image_size", "Image scaling", &ScaleMode),
- .ChoiceCount = 7, .Choices = { { "Aspect, fast", "aspect" }, { "Full, fast", "fullscreen" }, { "Aspect, bilinear", "aspect_bilinear" }, { "Full, bilinear", "fullscreen_bilinear" }, { "Aspect, sub-pixel", "aspect_subpixel" }, { "Full, sub-pixel", "fullscreen_subpixel" }, { "None", "original" } }
+ .ChoiceCount = 8, .Choices = { { "Aspect, fast", "aspect" }, { "Full, fast", "fullscreen" }, { "Aspect, bilinear", "aspect_bilinear" }, { "Full, bilinear", "fullscreen_bilinear" }, { "Aspect, sub-pixel", "aspect_subpixel" }, { "Full, sub-pixel", "fullscreen_subpixel" }, { "None", "original" }, { "Hardware", "hardware" } }
};
static struct MenuEntry PerGameDisplayMenu_Frameskip = {
@@ -1488,6 +1496,8 @@ u32 ReGBA_Menu(enum ReGBA_MenuEntryReason EntryReason)
usleep(5000);
}
+ SetMenuResolution();
+
struct Menu *ActiveMenu = &MainMenu, *PreviousMenu = ActiveMenu;
if (MainMenu.InitFunction != NULL)
{
@@ -1657,6 +1667,8 @@ u32 ReGBA_Menu(enum ReGBA_MenuEntryReason EntryReason)
usleep(5000);
}
+ SetGameResolution();
+
SDL_PauseAudio(SDL_DISABLE);
StatsStopFPS();
timespec Now;
diff --git a/source/opendingux/main.c b/source/opendingux/main.c
index b479a4a..accd2be 100644
--- a/source/opendingux/main.c
+++ b/source/opendingux/main.c
@@ -281,6 +281,8 @@ int main(int argc, char *argv[])
// We'll never actually return from here.
+ SetGameResolution();
+
execute_arm_translate(execute_cycles);
return 0;
}
diff --git a/source/opendingux/od-input.c b/source/opendingux/od-input.c
index b6c242b..ecccaf4 100644
--- a/source/opendingux/od-input.c
+++ b/source/opendingux/od-input.c
@@ -203,6 +203,8 @@ static bool WasSaveStateHeld = false;
void ProcessSpecialKeys()
{
+ enum OpenDingux_Buttons ButtonCopy = LastButtons;
+
enum OpenDingux_Buttons FastForwardToggle = ResolveButtons(Hotkeys[2], PerGameHotkeys[2]);
bool IsFastForwardToggleHeld = FastForwardToggle != 0 && (FastForwardToggle & LastButtons) == FastForwardToggle;
if (!WasFastForwardToggleHeld && IsFastForwardToggleHeld)
@@ -212,15 +214,16 @@ void ProcessSpecialKeys()
// Resolve fast-forwarding. It is activated if it's either toggled by the
// Toggle hotkey, or the While Held key is held down.
enum OpenDingux_Buttons FastForwardWhileHeld = ResolveButtons(Hotkeys[0], PerGameHotkeys[0]);
- bool IsFastForwardWhileHeld = FastForwardWhileHeld != 0 && (FastForwardWhileHeld & LastButtons) == FastForwardWhileHeld;
+ bool IsFastForwardWhileHeld = FastForwardWhileHeld != 0 && (FastForwardWhileHeld & ButtonCopy) == FastForwardWhileHeld;
FastForwardFrameskip = (IsFastForwardToggled || IsFastForwardWhileHeld)
? ResolveSetting(FastForwardTarget, PerGameFastForwardTarget) + 1
: 0;
enum OpenDingux_Buttons LoadState = ResolveButtons(Hotkeys[3], PerGameHotkeys[3]);
- bool IsLoadStateHeld = LoadState != 0 && (LoadState & LastButtons) == LoadState;
+ bool IsLoadStateHeld = LoadState != 0 && (LoadState & ButtonCopy) == LoadState;
if (!WasLoadStateHeld && IsLoadStateHeld)
{
+ SetMenuResolution();
switch (load_state(0))
{
case 1:
@@ -234,14 +237,16 @@ void ProcessSpecialKeys()
ShowErrorScreen("Reading saved state #1 failed:\nFile format invalid");
break;
}
+ SetGameResolution();
}
WasLoadStateHeld = IsLoadStateHeld;
enum OpenDingux_Buttons SaveState = ResolveButtons(Hotkeys[4], PerGameHotkeys[4]);
- bool IsSaveStateHeld = SaveState != 0 && (SaveState & LastButtons) == SaveState;
+ bool IsSaveStateHeld = SaveState != 0 && (SaveState & ButtonCopy) == SaveState;
if (!WasSaveStateHeld && IsSaveStateHeld)
{
void* Screenshot = copy_screen();
+ SetMenuResolution();
if (Screenshot == NULL)
ShowErrorScreen("Gathering the screenshot for saved state #1 failed: Memory allocation error");
else
@@ -256,6 +261,7 @@ void ProcessSpecialKeys()
ShowErrorScreen("Writing saved state #1 failed:\nUnknown error");
}
}
+ SetGameResolution();
}
WasSaveStateHeld = IsSaveStateHeld;
}
diff --git a/source/opendingux/port.c b/source/opendingux/port.c
index a7398f0..4ad3d5a 100644
--- a/source/opendingux/port.c
+++ b/source/opendingux/port.c
@@ -115,7 +115,7 @@ void ReGBA_DisplayFPS(void)
sprintf(line, "%2u/%3u", Stats.RenderedFPS, Stats.EmulatedFPS);
// White text, black outline
ScaleModeUnapplied();
- PrintStringOutline(line, RGB888_TO_RGB565(255, 255, 255), RGB888_TO_RGB565(0, 0, 0), OutputSurface->pixels, OutputSurface->pitch, 7, 3, GCW0_SCREEN_WIDTH - 14, GCW0_SCREEN_HEIGHT - 6, LEFT, BOTTOM);
+ PrintStringOutline(line, RGB888_TO_RGB565(255, 255, 255), RGB888_TO_RGB565(0, 0, 0), OutputSurface->pixels, OutputSurface->pitch, 7, 3, OutputSurface->w - 14, OutputSurface->h - 6, LEFT, BOTTOM);
}
}