Skip to content

Commit

Permalink
Engine: reimplemented fade effects outside of gfx drivers
Browse files Browse the repository at this point in the history
Reimplemented each effect in screen.cpp, with a set of screen_effect_*() functions as transition "interface". Bring them to certain level of consistency in how they render and update frame.
Removed FadeIn(), FadeOut() and BoxOutEffect() methods from IGraphicsDriver, and respective implementations.
Removed redundant callbacks from gfx drivers.
Mark GameState.no_hicolor_fadein flag as deprecated, as it's purely an optimization, and should perhaps be a part of engine config rather than a part of script API.
  • Loading branch information
ivan-mogilko committed Nov 12, 2023
1 parent a753e25 commit 99ee717
Show file tree
Hide file tree
Showing 17 changed files with 418 additions and 627 deletions.
7 changes: 0 additions & 7 deletions Engine/ac/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,6 @@ void init_draw_method()

if (drawstate.SoftwareRender)
{
drawstate.SoftwareRender = true;
drawstate.WalkBehindMethod = DrawOverCharSprite;
}
else
Expand Down Expand Up @@ -1197,12 +1196,6 @@ void clear_letterbox_borders()
gfxDriver->ClearRectangle(0, viewport.Bottom + 1, game.GetGameRes().Width - 1, game.GetGameRes().Height - 1, nullptr);
}

void draw_game_screen_callback()
{
construct_game_scene(true);
construct_game_screen_overlay(false);
}

void putpixel_compensate (Bitmap *ds, int xx,int yy, int col) {
if ((ds->GetColorDepth() == 32) && (col != 0)) {
// ensure the alpha channel is preserved if it has one
Expand Down
2 changes: 0 additions & 2 deletions Engine/ac/draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,6 @@ void draw_gui_sprite(Common::Bitmap *ds, bool use_alpha, int xpos, int ypos,

// Render game on screen
void render_to_screen();
// Callbacks for the graphics driver
void draw_game_screen_callback();
void GfxDriverOnInitCallback(void *data);
bool GfxDriverSpriteEvtCallback(int evt, int data);
void putpixel_compensate (Common::Bitmap *g, int xx,int yy, int col);
Expand Down
130 changes: 23 additions & 107 deletions Engine/ac/event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ extern GameState play;
extern RGB palette[256];
extern IGraphicsDriver *gfxDriver;
extern AGSPlatformDriver *platform;
extern RGB old_palette[256];
extern int displayed_room;
extern ScriptHotspot scrHotspot[MAX_ROOM_HOTSPOTS];
extern CCHotspot ccDynamicHotspot;
// FIXME: refactor further to get rid of this extern, maybe move part of the code to screen.cpp?
extern std::unique_ptr<Bitmap> saved_viewport_bitmap;

int in_enters_screen=0,done_es_error = 0;
int in_leaves_screen = -1;
Expand Down Expand Up @@ -204,7 +205,11 @@ void process_event(const EventHappened *evp) {
if ((evp->data1 == EVB_ROOM) && (evp->data3 == EVROM_BEFOREFADEIN))
in_enters_screen --;
}
else if (evp->type==EV_FADEIN) {
else if (evp->type==EV_FADEIN)
{
// TODO: move most of this code into a separate function,
// see current_fade_out_effect() for example

debug_script_log("Transition-in in room %d", displayed_room);
// if they change the transition type before the fadein, make
// sure the screen doesn't freeze up
Expand Down Expand Up @@ -232,131 +237,42 @@ void process_event(const EventHappened *evp) {
// transition type was not crossfade/dissolve when the screen faded out,
// but it is now when the screen fades in (Eg. a save game was restored
// with a different setting). Therefore just fade normally.
fadeout_impl(5);
screen_effect_fade(false, 5);
theTransition = FADE_NORMAL;
}

// TODO: use normal coordinates instead of "native_size" and multiply_up_*?
const Rect &viewport = play.GetMainViewport();

if ((theTransition == FADE_INSTANT) || ignore_transition)
{
set_palette_range(palette, 0, 255, 0);
}
else if (theTransition == FADE_NORMAL)
{
fadein_impl(palette, 5);
screen_effect_fade(true, 5);
}
else if (theTransition == FADE_BOXOUT)
{
if (!gfxDriver->UsesMemoryBackBuffer())
{
gfxDriver->BoxOutEffect(false, get_fixed_pixel_size(16), 1000 / GetGameSpeed());
}
else
{
// First of all we render the game once again and save backbuffer from further editing.
// We put temporary bitmap as a new backbuffer for the transition period, and
// will be drawing saved image of the game over to that backbuffer, simulating "box-out".
set_palette_range(palette, 0, 255, 0);
construct_game_scene(true);
construct_game_screen_overlay(false);
gfxDriver->RenderToBackBuffer();
Bitmap *saved_backbuf = gfxDriver->GetMemoryBackBuffer();
Bitmap *temp_scr = new Bitmap(saved_backbuf->GetWidth(), saved_backbuf->GetHeight(), saved_backbuf->GetColorDepth());
gfxDriver->SetMemoryBackBuffer(temp_scr);
temp_scr->Clear();
render_to_screen();

const int speed = get_fixed_pixel_size(16);
const int yspeed = viewport.GetHeight() / (viewport.GetWidth() / speed);
int boxwid = speed, boxhit = yspeed;
while (boxwid < temp_scr->GetWidth())
{
boxwid += speed;
boxhit += yspeed;
boxwid = Math::Clamp(boxwid, 0, viewport.GetWidth());
boxhit = Math::Clamp(boxhit, 0, viewport.GetHeight());
int lxp = viewport.GetWidth() / 2 - boxwid / 2;
int lyp = viewport.GetHeight() / 2 - boxhit / 2;
temp_scr->Blit(saved_backbuf, lxp, lyp, lxp, lyp,
boxwid, boxhit);
render_to_screen();
WaitForNextFrame();
}
gfxDriver->SetMemoryBackBuffer(saved_backbuf);
}
play.screen_is_faded_out = 0;
screen_effect_box(true, get_fixed_pixel_size(16));
}
else if (theTransition == FADE_CROSSFADE)
{
if (game.color_depth == 1)
quit("!Cannot use crossfade screen transition in 256-colour games");

IDriverDependantBitmap *ddb = prepare_screen_for_transition_in();
for (int alpha = 254; alpha > 0; alpha -= 16)
{
// do the crossfade
ddb->SetAlpha(alpha);
invalidate_screen();
construct_game_scene(true);
construct_game_screen_overlay(false);
// draw old screen on top while alpha > 16
if (alpha > 16)
{
gfxDriver->BeginSpriteBatch(play.GetMainViewport(), SpriteTransform());
gfxDriver->DrawSprite(0, 0, ddb);
gfxDriver->EndSpriteBatch();
}
render_to_screen();
update_polled_stuff();
WaitForNextFrame();
}

delete saved_viewport_bitmap;
saved_viewport_bitmap = nullptr;
set_palette_range(palette, 0, 255, 0);
gfxDriver->DestroyDDB(ddb);
screen_effect_crossfade();
}
else if (theTransition == FADE_DISSOLVE) {
int pattern[16]={0,4,14,9,5,11,2,8,10,3,12,7,15,6,13,1};
int aa,bb,cc;
RGB interpal[256];

IDriverDependantBitmap *ddb = prepare_screen_for_transition_in();
for (aa=0;aa<16;aa++) {
// merge the palette while dithering
if (game.color_depth == 1)
{
fade_interpolate(old_palette,palette,interpal,aa*4,0,255);
set_palette_range(interpal, 0, 255, 0);
}
// do the dissolving
int maskCol = saved_viewport_bitmap->GetMaskColor();
for (bb=0;bb<viewport.GetWidth();bb+=4) {
for (cc=0;cc<viewport.GetHeight();cc+=4) {
saved_viewport_bitmap->PutPixel(bb+pattern[aa]/4, cc+pattern[aa]%4, maskCol);
}
}
gfxDriver->UpdateDDBFromBitmap(ddb, saved_viewport_bitmap, false);
construct_game_scene(true);
construct_game_screen_overlay(false);
gfxDriver->BeginSpriteBatch(play.GetMainViewport(), SpriteTransform());
gfxDriver->DrawSprite(0, 0, ddb);
gfxDriver->EndSpriteBatch();
render_to_screen();
update_polled_stuff();
WaitForNextFrame();
}

delete saved_viewport_bitmap;
saved_viewport_bitmap = nullptr;
set_palette_range(palette, 0, 255, 0);
gfxDriver->DestroyDDB(ddb);
else if (theTransition == FADE_DISSOLVE)
{
screen_effect_dissolve();
}

}
else if (evp->type==EV_IFACECLICK)
else if (evp->type == EV_IFACECLICK)
{
process_interface_click(evp->data1, evp->data2, evp->data3);
else quit("process_event: unknown event to process");
}
else
{
quit("process_event: unknown event to process");
}
}


Expand Down
2 changes: 1 addition & 1 deletion Engine/ac/gamestate.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ struct GameState
int used_inv_on = 0; // inv item they clicked on
int no_textbg_when_voice = 0; // no textwindow bgrnd when voice speech is used
int max_dialogoption_width = 0; // max width of dialog options text window
int no_hicolor_fadein = 0; // fade out but instant in for hi-color
int no_hicolor_fadein = 0; // (DEPRECATED, lo-end optimization) fade out but instant in for hi-color
int bgspeech_game_speed = 0; // is background speech relative to game speed
int bgspeech_stay_on_display = 0; // whether to remove bg speech when DisplaySpeech is used
int unfactor_speech_from_textlength = 0; // remove "&10" when calculating time for text to stay
Expand Down
14 changes: 2 additions & 12 deletions Engine/ac/global_screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,20 +142,10 @@ void FadeOut(int sppd) {
// 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);
screen_effect_fade(false, sppd);
sync_audio_playback();
}

void fadeout_impl(int spdd) {
if (play.screen_is_faded_out == 0)
{
gfxDriver->FadeOut(spdd, play.fade_to_red, play.fade_to_green, play.fade_to_blue);
}

if (game.color_depth > 1)
play.screen_is_faded_out = 1;
}

void SetScreenTransition(int newtrans) {
if ((newtrans < 0) || (newtrans > FADE_LAST))
quit("!SetScreenTransition: invalid transition type");
Expand Down Expand Up @@ -193,6 +183,6 @@ void FadeIn(int sppd) {
// 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(palette,sppd);
screen_effect_fade(true, sppd);
sync_audio_playback();
}
Loading

0 comments on commit 99ee717

Please sign in to comment.