Files
scummvm-cursorfix/engines/ags/engine/ac/global_screen.cpp
2026-02-02 04:50:13 +01:00

210 lines
6.1 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ags/shared/ac/common.h"
#include "ags/engine/ac/game_setup.h"
#include "ags/engine/ac/draw.h"
#include "ags/engine/ac/game_setup.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/engine/ac/game_state.h"
#include "ags/engine/ac/global_game.h"
#include "ags/engine/ac/global_screen.h"
#include "ags/engine/ac/runtime_defines.h"
#include "ags/engine/ac/screen.h"
#include "ags/engine/debugging/debug_log.h"
#include "ags/engine/main/game_run.h"
#include "ags/engine/media/audio/audio.h"
#include "ags/engine/platform/base/ags_platform_driver.h"
#include "ags/engine/gfx/graphics_driver.h"
#include "ags/shared/gfx/bitmap.h"
namespace AGS3 {
using namespace AGS::Shared;
using namespace AGS::Engine;
void FlipScreen(int amount) {
if ((amount < 0) || (amount > 3))
quit("!FlipScreen: invalid argument (0-3)");
_GP(play).screen_flipped = amount;
}
void ShakeScreen(int severe) {
EndSkippingUntilCharStops();
if (_GP(play).fast_forward)
return;
severe = data_to_game_coord(severe);
// TODO: support shaking room viewport separately
// TODO: rely on game speed setting? and/or provide frequency and duration args
// TODO: unify blocking and non-blocking shake update
_GP(play).shakesc_length = 10;
_GP(play).shakesc_delay = 2;
_GP(play).shakesc_amount = severe;
_GP(play).mouse_cursor_hidden++;
// FIXME: we have to sync audio here explicitly, because ShakeScreen
// does not call any game update function while it works
sync_audio_playback();
if (_G(gfxDriver)->RequiresFullRedrawEachFrame()) {
for (int hh = 0; hh < 40; hh++) {
_G(loopcounter)++;
_G(platform)->Delay(50);
render_graphics();
update_polled_stuff();
}
} else {
// Optimized variant for software render: create game scene once and shake it
construct_game_scene();
_G(gfxDriver)->RenderToBackBuffer();
for (int hh = 0; hh < 40; hh++) {
_G(platform)->Delay(50);
const int yoff = hh % 2 == 0 ? 0 : severe;
_GP(play).shake_screen_yoff = yoff;
render_to_screen();
update_polled_stuff();
}
clear_letterbox_borders();
render_to_screen();
}
sync_audio_playback();
_GP(play).mouse_cursor_hidden--;
_GP(play).shakesc_length = 0;
_GP(play).shakesc_delay = 0;
_GP(play).shakesc_amount = 0;
}
void ShakeScreenBackground(int delay, int amount, int length) {
if (delay < 2)
quit("!ShakeScreenBackground: invalid delay parameter");
amount = data_to_game_coord(amount);
if (amount < _GP(play).shakesc_amount) {
// from a bigger to smaller shake, clear up the borders
clear_letterbox_borders();
}
_GP(play).shakesc_amount = amount;
_GP(play).shakesc_delay = delay;
_GP(play).shakesc_length = length;
}
void TintScreen(int red, int grn, int blu) {
if ((red < 0) || (grn < 0) || (blu < 0) || (red > 100) || (grn > 100) || (blu > 100))
quit("!TintScreen: RGB values must be 0-100");
invalidate_screen();
if ((red == 0) && (grn == 0) && (blu == 0)) {
_GP(play).screen_tint = -1;
return;
}
red = (red * 25) / 10;
grn = (grn * 25) / 10;
blu = (blu * 25) / 10;
_GP(play).screen_tint = red + (grn << 8) + (blu << 16);
}
void FadeOut(int sppd) {
EndSkippingUntilCharStops();
if (_GP(play).fast_forward) {
_GP(play).screen_is_faded_out = 1;
return;
}
// FIXME: we have to sync audio here explicitly, because FadeOut
// does not call any game update function while it works
sync_audio_playback();
fadeout_impl(sppd);
sync_audio_playback();
// Older engines did not mark the screen as "faded out" specifically for
// the 8-bit games, for unknown reasons. There's at least one game where
// this was accidentally useful, as it did not run FadeIn after FadeOut.
if ((_G(loaded_game_file_version) < kGameVersion_361) && _GP(game).color_depth == 1) {
_GP(play).screen_is_faded_out = 0;
}
}
void fadeout_impl(int spdd) {
if (_GP(play).screen_is_faded_out == 0) {
_G(gfxDriver)->FadeOut(spdd, _GP(play).fade_to_red, _GP(play).fade_to_green, _GP(play).fade_to_blue, RENDER_SHOT_SKIP_ON_FADE);
_GP(play).screen_is_faded_out = 1;
}
}
void SetScreenTransition(int newtrans) {
if ((newtrans < 0) || (newtrans > FADE_LAST))
quit("!SetScreenTransition: invalid transition type");
_GP(play).fade_effect = newtrans;
debug_script_log("Screen transition changed");
}
void SetNextScreenTransition(int newtrans) {
if ((newtrans < 0) || (newtrans > FADE_LAST))
quit("!SetNextScreenTransition: invalid transition type");
_GP(play).next_screen_transition = newtrans;
debug_script_log("SetNextScreenTransition engaged");
}
void SetFadeColor(int red, int green, int blue) {
if ((red < 0) || (red > 255) || (green < 0) || (green > 255) ||
(blue < 0) || (blue > 255))
quit("!SetFadeColor: Red, Green and Blue must be 0-255");
_GP(play).fade_to_red = red;
_GP(play).fade_to_green = green;
_GP(play).fade_to_blue = blue;
}
void FadeIn(int sppd) {
EndSkippingUntilCharStops();
if (_GP(play).fast_forward) {
_GP(play).screen_is_faded_out = 0;
return;
}
// Update drawables, prepare them for the transition-in
// in case this is called after the game state change but before any update was run
SyncDrawablesState();
// FIXME: we have to sync audio here explicitly, because FadeIn
// does not call any game update function while it works
sync_audio_playback();
fadein_impl(_G(palette), sppd);
sync_audio_playback();
}
} // namespace AGS3