From db690ea7ff26e15279781ac2851d6eeac57ec36b Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 2 Apr 2026 22:25:04 -0700
Subject: [PATCH] Added an official zoom mode
---
Data/Images/zoom-in.png | Bin 0 -> 781 bytes
Data/Images/zoom-out.png | Bin 0 -> 422 bytes
Data/UI/game.xml | 36 +++++++--
game/Maelstrom_Globals.h | 1 +
game/controls.cpp | 2 +
game/game.cpp | 159 +++++++++++++++++----------------------
game/game.h | 8 +-
game/init.cpp | 4 +-
8 files changed, 108 insertions(+), 102 deletions(-)
create mode 100644 Data/Images/zoom-in.png
create mode 100644 Data/Images/zoom-out.png
diff --git a/Data/Images/zoom-in.png b/Data/Images/zoom-in.png
new file mode 100644
index 0000000000000000000000000000000000000000..d38fbf3bff92715887b9dcbdf045caa5f81d17b1
GIT binary patch
literal 781
zcmV+o1M>WdP)<h;3K|Lk000e1NJLTq001EX001Bm1^@s6%qY!?0008iNkl<ZXx{CZ
z%S%*o6vyu!#~B|vjg6^6k&&Wg4MI>;0}=G1sD+E7hhd8#i2eX+*(&G(1>qv1h#*3G
zV2dIu+7voW;v%wHNF!-!`6{(}__!^;A6vAlV4QL0p3R4I@9*B<`JH=y=bYa)3|nlm
z#g+^d%d#xXGCDHF9!Gi{kbhiS{YUBkpy<7nD-qy?kHvFQ@!3{!$prUTWo<;5rfHg{
zF(a*@TrA%%dXr-1DTa?Nv?HA9iH`!9zfX+KibYRx*ksn{2+4TAm>9<a2gT8=Yz=>o
zIO6xb@8D}P$(eN7l_p1cdqme0@#iklSIpMv&XF9E*eT9jWNY+sy^yWp!yzLX>j(^8
zgF2toYG9lNbTO`h>qYPr$&qY1o8YbM#liUotBL13(ci-ra5)@;!?2e5J5uHd8Rm{)
z$2zg@t~k-fPK#+=$x-}N&4M3^CExH%kaF21&XFTd@LXpl(>@S9Wnz-|#p-y^bE?m6
zF;cDhV;|&@uZ@3Q-v7-JPM@?38^z#eaW#Fw55Ck0kx-gPPPj=xu=gEAKs^g|T@gcb
zV#RqDxJ4YeMcLiM{rg1FQXI65`$Wd>kR0))Cq-MMkdCkI0ETQ6rwQ4-I~ata@fN=L
zNzsjCtb2S}o~!7^5zS)X3no0w`!+C76}bgF^2016$__e>9hZ6Dm+Dsex|sJCy#>-T
zyBg4Y;djPA<gBq)Y;6?7VX<aNG(9{w%=jJXAvg)&5UG9Wql@g!QCchBI4izlA^z@k
z*_Ed9IYqTePLV|Say`J8ts?tJv(6DLkQ|Y0C3g%^RXB5uMgAz43+9N0K7Dey^0blc
zigC<J+Js~O+XpPt7Tcma7}s#qXY?ak|A%V+#|#Zvj4~J?GT0&mhZq;gksmYec5=fs
zW(<mDafbKj$S*thCUL(@Y;G5Q)kdxfjTe1{<E3GXEw<QVOXkZjuifG|vQ-pv00000
LNkvXXu0mjf)J1rZ
literal 0
HcmV?d00001
diff --git a/Data/Images/zoom-out.png b/Data/Images/zoom-out.png
new file mode 100644
index 0000000000000000000000000000000000000000..507cd2f1cffa9c1b3695380ad00700d2bdf3b1ab
GIT binary patch
literal 422
zcmV;X0a^ZuP)<h;3K|Lk000e1NJLTq001EX001Bm1^@s6%qY!?0004PNkl<ZXx{DD
z&nts*90%~{+4gKGKV~gIO01|6wK&X=a#5Td-24Gb`3sh_gHp=bfwGdM`~kR87IMN4
zYD+T0fz>oWz7FsAWlkm&dA~2OK6`q;-_Q56XRF7u6h%=KMNt$*QIy{kV~jDz3eh0#
zr`<o?M;rCi-mk7_7q_u5i7MCu!>jP|2)c5xvI%Be;p-+p--Q(!7@CCp^)Q+#tgQu5
z<-mM9%!Rqm7IbD{lKbV(Y}>YN`(~^}gYX1U&Go>6C~VHdhakL*K))N-EWwLo4y+SC
zufV!lcpWROoj!QE49iA%eFJ8yIiOlzzlFmI4C3nav*+^^_W+gin_eGfBZE9p19ZpP
z5F35s!QLjIkApF5u#xwtw>i)cwKdN5y0}jZd|@BX0gsV_CsXWWp7#ez{o7oG?nBlw
znu6X4>+|o~&l%!+37VyQd{Wb_@AWUPD2k#e%0GK~^G-w8jwYfgit-2Y4$C~y(P1;q
Q(EtDd07*qoM6N<$f>zVVk^lez
literal 0
HcmV?d00001
diff --git a/Data/UI/game.xml b/Data/UI/game.xml
index 88aacf10..5f574aa5 100644
--- a/Data/UI/game.xml
+++ b/Data/UI/game.xml
@@ -122,6 +122,20 @@
</Image>
</Elements>
</Button>
+ <Button name="zoom" action="CONTROL_ZOOM" image="circle">
+ <Size w="30" h="30"/>
+ <Anchor anchorFrom="TOP" anchorTo="BOTTOM" anchor="pause" y="8"/>
+ <Elements>
+ <Image name="zoom_in" image="zoom-in">
+ <Size w="24" h="24"/>
+ <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
+ </Image>
+ <Image name="zoom_out" image="zoom-out">
+ <Size w="24" h="24"/>
+ <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
+ </Image>
+ </Elements>
+ </Button>
<Thumbstick image="split-circle">
<Size w="85" h="85"/>
@@ -199,6 +213,20 @@
</Image>
</Elements>
</Button>
+ <Button name="zoom" action="CONTROL_ZOOM" image="circle">
+ <Size w="45" h="45"/>
+ <Anchor anchorFrom="TOP" anchorTo="BOTTOM" anchor="pause" y="12"/>
+ <Elements>
+ <Image name="zoom_in" image="zoom-in">
+ <Size w="36" h="36"/>
+ <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
+ </Image>
+ <Image name="zoom_out" image="zoom-out">
+ <Size w="36" h="36"/>
+ <Anchor anchorFrom="CENTER" anchorTo="CENTER"/>
+ </Image>
+ </Elements>
+ </Button>
<Thumbstick image="split-circle">
<Size w="128" h="128"/>
@@ -253,13 +281,5 @@
</Elements>
</Area>
-
- <Button name="test_button" action="CONTROL_TEST" image="circle">
- <Size w="45" h="45"/>
- <Anchor anchorFrom="TOP" anchorTo="TOP" y="8"/>
- </Button>
- <Label name="test_label" template="SmallYellow">
- <Anchor anchorFrom="LEFT" anchorTo="RIGHT" anchor="test_button" x="4"/>
- </Label>
</Elements>
</Panel>
diff --git a/game/Maelstrom_Globals.h b/game/Maelstrom_Globals.h
index 22a49026..f3ecbc9a 100644
--- a/game/Maelstrom_Globals.h
+++ b/game/Maelstrom_Globals.h
@@ -142,6 +142,7 @@ extern Replay gReplay;
extern Controls controls;
extern PrefsVariable<int> gSoundLevel;
extern PrefsVariable<int> gGammaCorrect;
+extern PrefsVariable<int> gZoomGame;
// int scores.cpp :
extern Scores hScores[NUM_SCORES];
diff --git a/game/controls.cpp b/game/controls.cpp
index 84ccb5c4..c7ec3d77 100644
--- a/game/controls.cpp
+++ b/game/controls.cpp
@@ -58,12 +58,14 @@ Controls::Bind(Prefs *prefs)
Controls controls;
PrefsVariable<int> gSoundLevel("SoundLevel", 4);
PrefsVariable<int> gGammaCorrect("GammaCorrect", 3);
+PrefsVariable<int> gZoomGame("ZoomGame", 0);
void LoadControls(void)
{
gSoundLevel.Bind(prefs);
gGammaCorrect.Bind(prefs);
+ gZoomGame.Bind(prefs);
controls.Bind(prefs);
}
diff --git a/game/game.cpp b/game/game.cpp
index 07ed182a..01502168 100644
--- a/game/game.cpp
+++ b/game/game.cpp
@@ -185,8 +185,8 @@ GamePanelDelegate::OnLoad()
m_frags = m_panel->GetElement<UIElement>("frags");
m_paused = m_panel->GetElement<UIElement>("paused");
-
- m_zoom = false;
+ m_zoomIn = m_panel->GetElement<UIElement>("zoom_in");
+ m_zoomOut = m_panel->GetElement<UIElement>("zoom_out");
return true;
}
@@ -490,9 +490,7 @@ GamePanelDelegate::OnDraw(DRAWLEVEL drawLevel)
return;
}
- if (m_zoom) {
- StartZoomedDrawing();
- }
+ StartZoomedDrawing();
/* -- Draw the star field */
for ( i=0; i<MAX_STARS; ++i ) {
@@ -514,9 +512,7 @@ GamePanelDelegate::OnDraw(DRAWLEVEL drawLevel)
DrawBorder();
- if (m_zoom) {
- StopZoomedDrawing();
- }
+ StopZoomedDrawing();
}
bool
@@ -527,15 +523,12 @@ GamePanelDelegate::HandleEvent(const SDL_Event &event)
m_touchControls->Show();
}
} else if (event.type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED ||
- event.type == SDL_EVENT_WINDOW_SAFE_AREA_CHANGED ||
- event.type == SDL_EVENT_REMOTE_PLAYERS_CHANGED) {
+ event.type == SDL_EVENT_WINDOW_SAFE_AREA_CHANGED) {
UpdateZoom();
}
return false;
}
-static int gZoomMode = 0;
-
bool
GamePanelDelegate::OnAction(UIBaseElement *sender, const char *action)
{
@@ -568,9 +561,8 @@ GamePanelDelegate::OnAction(UIBaseElement *sender, const char *action)
control = PAUSE_KEY;
} else if (SDL_strcasecmp(action, "ABORT") == 0) {
control = ABORT_KEY;
- } else if (SDL_strcasecmp(action, "TEST") == 0) {
- gZoomMode = (gZoomMode + 1) % 3;
- UpdateZoom();
+ } else if (SDL_strcasecmp(action, "ZOOM") == 0) {
+ ToggleZoomGame();
return true;
} else {
error("Unknown control action '%s'", action);
@@ -610,73 +602,60 @@ GamePanelDelegate::UpdateZoom()
SDL_GetRenderSafeArea(renderer, &rect);
SDL_SetRenderLogicalPresentation(renderer, saved_w, saved_h, saved_mode);
- // We can zoom if we're on a phone in landscape mode and not local multiplayer
- bool zoom = false;
-
- if (IsPhone() && rect.w > rect.h) {
- int i;
-
- int local_players = 0;
- OBJ_LOOP(i, MAX_PLAYERS) {
- if (!gPlayers[i]->IsValid()) {
- continue;
- }
+ if (IsPhone() || IsTablet() || gZoomGame) {
+ StartZoomUI(rect);
+ } else {
+ StopZoomUI();
+ }
- if (IS_LOCAL_CONTROL(gPlayers[i]->GetControlType())) {
- ++local_players;
- }
+ if (gZoomGame) {
+ if (!m_texture) {
+ m_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_TARGET, GAME_WIDTH, GAME_HEIGHT);
}
- if (local_players == 1) {
- zoom = true;
+ if (m_zoomIn) {
+ m_zoomIn->Hide();
+ }
+ if (m_zoomOut) {
+ m_zoomOut->Show();
}
- }
- if (gZoomMode == 0 || (gZoomMode == -1 && !zoom)) {
- m_panel->GetElement<UIElement>("test_label")->SetText("(0) Zoom disabled");
- } else if (gZoomMode == 1 || (gZoomMode == -1 && zoom)) {
- zoom = true;
- m_panel->GetElement<UIElement>("test_label")->SetText("(1) Zoomed and centered on ship");
- } else if (gZoomMode == 2) {
- zoom = true;
- m_panel->GetElement<UIElement>("test_label")->SetText("(2) Zoomed and ship moves freely");
- }
-
- if (zoom) {
- StartZoom(rect);
} else {
- StopZoom();
+ if (m_texture) {
+ SDL_DestroyTexture(m_texture);
+ m_texture = nullptr;
+ }
+ if (m_zoomIn) {
+ m_zoomIn->Show();
+ }
+ if (m_zoomOut) {
+ m_zoomOut->Hide();
+ }
}
}
void
-GamePanelDelegate::StartZoom(const SDL_Rect &rect)
+GamePanelDelegate::StartZoomUI(const SDL_Rect &rect)
{
- SDL_Renderer *renderer = screen->GetRenderer();
float scale = (float)GAME_WIDTH / rect.w;
int x = (int)SDL_round(rect.x * scale);
int y = (int)SDL_round(rect.y * scale);
int height = (int)SDL_round(rect.h * scale);
ui->SetPosition(x, y);
ui->SetSize(GAME_WIDTH, height);
-
- if (!m_texture) {
- m_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_TARGET, GAME_WIDTH, GAME_HEIGHT);
- }
-
- m_zoom = true;
}
void
-GamePanelDelegate::StopZoom()
+GamePanelDelegate::StopZoomUI()
{
ui->SetPosition(0, 0);
ui->SetSize(GAME_WIDTH, GAME_HEIGHT);
+}
- if (m_texture) {
- SDL_DestroyTexture(m_texture);
- m_texture = nullptr;
- }
+void
+GamePanelDelegate::ToggleZoomGame()
+{
+ gZoomGame = !gZoomGame;
- m_zoom = false;
+ UpdateZoom();
}
void
@@ -684,17 +663,20 @@ GamePanelDelegate::StartZoomedDrawing()
{
SDL_Renderer *renderer = screen->GetRenderer();
+ if (!gZoomGame) {
+ screen->SetLogicalSize(GAME_WIDTH, GAME_HEIGHT);
+ return;
+ }
+
screen->GetClip(&m_savedClip);
- if (gZoomMode != 0) {
- // Don't clip
- SDL_Rect clip;
- clip.y = 0;
- clip.x = 0;
- clip.w = GAME_WIDTH;
- clip.h = GAME_HEIGHT;
- screen->ClipBlit(&clip);
- }
+ // Don't clip
+ SDL_Rect clip;
+ clip.y = 0;
+ clip.x = 0;
+ clip.w = GAME_WIDTH;
+ clip.h = GAME_HEIGHT;
+ screen->ClipBlit(&clip);
SDL_SetRenderTarget(renderer, m_texture);
screen->Clear();
@@ -705,32 +687,26 @@ GamePanelDelegate::StopZoomedDrawing()
{
SDL_Renderer *renderer = screen->GetRenderer();
+ if (!gZoomGame) {
+ screen->SetLogicalSize(ui->X() + ui->Width() + ui->X(), ui->Y() + ui->Height() + ui->Y());
+ return;
+ }
+
SDL_SetRenderTarget(renderer, nullptr);
SDL_SetRenderLogicalPresentation(renderer, 0, 0, SDL_LOGICAL_PRESENTATION_DISABLED);
int w = 0, h = 0;
SDL_GetRenderOutputSize(renderer, &w, &h);
+ int cameraX, cameraY;
+ gPlayers[0]->GetCameraPos(&cameraX, &cameraY);
+ GetRenderCoordinates(cameraX, cameraY);
+
SDL_Rect src;
- if (gZoomMode == 0) {
- src.x = 0;
- src.y = 0;
- src.w = GAME_WIDTH;
- src.h = GAME_HEIGHT;
- } else if (gZoomMode == 1 || gZoomMode == -1) {
- int cameraX, cameraY;
- gPlayers[0]->GetCameraPos(&cameraX, &cameraY);
- GetRenderCoordinates(cameraX, cameraY);
- cameraX += (SPRITES_WIDTH / 2);
- cameraY += (SPRITES_WIDTH / 2);
-
- src.w = GAME_WIDTH;
- src.h = GAME_HEIGHT;
- src.x = cameraX - src.w / 2;
- src.y = cameraY - src.h / 2;
- } else if (gZoomMode == 2) {
- src = m_savedClip;
- }
+ src.w = m_savedClip.w;
+ src.h = m_savedClip.h;
+ src.x = cameraX - src.w / 2;
+ src.y = cameraY - src.h / 2;
float minu = (float)src.x / m_texture->w;
float minv = (float)src.y / m_texture->h;
@@ -802,7 +778,7 @@ GamePanelDelegate::StopZoomedDrawing()
void
GamePanelDelegate::DrawBorder()
{
- if (m_zoom && gZoomMode != 0) {
+ if (gZoomGame) {
return;
}
@@ -1521,7 +1497,12 @@ GamePanelDelegate::GameOver()
ui->ShowPanel(PANEL_GAMEOVER);
- StopZoom();
+ StopZoomUI();
+
+ if (m_texture) {
+ SDL_DestroyTexture(m_texture);
+ m_texture = nullptr;
+ }
}
/* ----------------------------------------------------------------- */
diff --git a/game/game.h b/game/game.h
index fd7e8029..852652d3 100644
--- a/game/game.h
+++ b/game/game.h
@@ -42,8 +42,9 @@ class GamePanelDelegate : public UIPanelDelegate
protected:
void UpdateZoom();
- void StartZoom(const SDL_Rect &rect);
- void StopZoom();
+ void StartZoomUI(const SDL_Rect &rect);
+ void StopZoomUI();
+ void ToggleZoomGame();
void StartZoomedDrawing();
void StopZoomedDrawing();
void DrawBorder();
@@ -88,6 +89,8 @@ class GamePanelDelegate : public UIPanelDelegate
UIElement *m_frags;
UIElement *m_paused;
+ UIElement *m_zoomIn;
+ UIElement *m_zoomOut;
enum {
STATE_PLAYING,
@@ -105,7 +108,6 @@ class GamePanelDelegate : public UIPanelDelegate
STATE_START_NEXT_WAVE,
} m_state;
- bool m_zoom;
SDL_Texture *m_texture = nullptr;
SDL_Rect m_savedClip;
};
diff --git a/game/init.cpp b/game/init.cpp
index 3c122f60..cf2923fb 100644
--- a/game/init.cpp
+++ b/game/init.cpp
@@ -220,8 +220,8 @@ static void DrawLoadBar()
void SetStar(int which)
{
- int x = FastRandom(GAME_WIDTH);
- int y = FastRandom(GAME_HEIGHT);
+ int x = FastRandom(GAME_WIDTH - 2*SPRITES_WIDTH) + SPRITES_WIDTH;
+ int y = FastRandom(GAME_HEIGHT - 2*SPRITES_WIDTH) + SPRITES_WIDTH;
gTheStars[which]->xCoord = x;
gTheStars[which]->yCoord = y;