From 9b485e31564f870a2ee87f01d58eaa39a4a87aaa Mon Sep 17 00:00:00 2001 From: Ghabry Date: Wed, 1 Sep 2021 16:34:08 +0200 Subject: [PATCH 1/9] Bitmap: Support specifying of a Pixman Blend Mode for most Blit functions. The until now unused variable "blend_type_effect" in Sprite is used to configure the blend mode. --- src/bitmap.cpp | 52 +++++++++++++++++++++------------------- src/bitmap.h | 65 +++++++++++++++++++++++++++++++++++--------------- src/sprite.cpp | 6 ++--- src/sprite.h | 2 +- 4 files changed, 78 insertions(+), 47 deletions(-) diff --git a/src/bitmap.cpp b/src/bitmap.cpp index bf13d72ae0..5264efd9fb 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -569,14 +569,14 @@ namespace { } } // anonymous namespace -void Bitmap::Blit(int x, int y, Bitmap const& src, Rect const& src_rect, Opacity const& opacity) { +void Bitmap::Blit(int x, int y, Bitmap const& src, Rect const& src_rect, Opacity const& opacity, int blend_mode) { if (opacity.IsTransparent()) { return; } auto mask = CreateMask(opacity, src_rect); - pixman_image_composite32(src.GetOperator(mask.get()), + pixman_image_composite32(src.GetOperator(mask.get(), blend_mode), src.bitmap.get(), mask.get(), bitmap.get(), src_rect.x, src_rect.y, @@ -605,11 +605,11 @@ PixmanImagePtr Bitmap::GetSubimage(Bitmap const& src, const Rect& src_rect) { (uint32_t*) pixels, src.pitch()) }; } -void Bitmap::TiledBlit(Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, Opacity const& opacity) { - TiledBlit(0, 0, src_rect, src, dst_rect, opacity); +void Bitmap::TiledBlit(Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, Opacity const& opacity, int blend_mode) { + TiledBlit(0, 0, src_rect, src, dst_rect, opacity, blend_mode); } -void Bitmap::TiledBlit(int ox, int oy, Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, Opacity const& opacity) { +void Bitmap::TiledBlit(int ox, int oy, Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, Opacity const& opacity, int blend_mode) { if (opacity.IsTransparent()) { return; } @@ -625,7 +625,7 @@ void Bitmap::TiledBlit(int ox, int oy, Rect const& src_rect, Bitmap const& src, auto mask = CreateMask(opacity, src_rect); - pixman_image_composite32(src.GetOperator(mask.get()), + pixman_image_composite32(src.GetOperator(mask.get(), blend_mode), src_bm.get(), mask.get(), bitmap.get(), ox, oy, 0, 0, @@ -633,11 +633,11 @@ void Bitmap::TiledBlit(int ox, int oy, Rect const& src_rect, Bitmap const& src, dst_rect.width, dst_rect.height); } -void Bitmap::StretchBlit(Bitmap const& src, Rect const& src_rect, Opacity const& opacity) { - StretchBlit(GetRect(), src, src_rect, opacity); +void Bitmap::StretchBlit(Bitmap const& src, Rect const& src_rect, Opacity const& opacity, int blend_mode) { + StretchBlit(GetRect(), src, src_rect, opacity, blend_mode); } -void Bitmap::StretchBlit(Rect const& dst_rect, Bitmap const& src, Rect const& src_rect, Opacity const& opacity) { +void Bitmap::StretchBlit(Rect const& dst_rect, Bitmap const& src, Rect const& src_rect, Opacity const& opacity, int blend_mode) { if (opacity.IsTransparent()) { return; } @@ -651,7 +651,7 @@ void Bitmap::StretchBlit(Rect const& dst_rect, Bitmap const& src, Rect const& sr auto mask = CreateMask(opacity, src_rect, &xform); - pixman_image_composite32(src.GetOperator(mask.get()), + pixman_image_composite32(src.GetOperator(mask.get(), blend_mode), src.bitmap.get(), mask.get(), bitmap.get(), src_rect.x / zoom_x, src_rect.y / zoom_y, 0, 0, @@ -661,7 +661,7 @@ void Bitmap::StretchBlit(Rect const& dst_rect, Bitmap const& src, Rect const& sr pixman_image_set_transform(src.bitmap.get(), nullptr); } -void Bitmap::WaverBlit(int x, int y, double zoom_x, double zoom_y, Bitmap const& src, Rect const& src_rect, int depth, double phase, Opacity const& opacity) { +void Bitmap::WaverBlit(int x, int y, double zoom_x, double zoom_y, Bitmap const& src, Rect const& src_rect, int depth, double phase, Opacity const& opacity, int blend_mode) { if (opacity.IsTransparent()) { return; } @@ -686,7 +686,7 @@ void Bitmap::WaverBlit(int x, int y, double zoom_x, double zoom_y, Bitmap const& const double sy = (i - yclip) * (2 * M_PI) / (32.0 * zoom_y); const int offset = 2 * zoom_x * depth * std::sin(phase + sy); - pixman_image_composite32(src.GetOperator(mask.get()), + pixman_image_composite32(src.GetOperator(mask.get(), blend_mode), src.bitmap.get(), mask.get(), bitmap.get(), xoff, yoff + i, 0, i, @@ -946,7 +946,7 @@ void Bitmap::BlendBlit(int x, int y, Bitmap const& src, Rect const& src_rect, co src_rect.width, src_rect.height); } -void Bitmap::FlipBlit(int x, int y, Bitmap const& src, Rect const& src_rect, bool horizontal, bool vertical, Opacity const& opacity) { +void Bitmap::FlipBlit(int x, int y, Bitmap const& src, Rect const& src_rect, bool horizontal, bool vertical, Opacity const& opacity, int blend_mode) { if (opacity.IsTransparent()) { return; } @@ -967,7 +967,7 @@ void Bitmap::FlipBlit(int x, int y, Bitmap const& src, Rect const& src_rect, boo rect = Rect{ src_x, src_y, src_rect.width, src_rect.height }; } - Blit(x, y, src, rect, opacity); + Blit(x, y, src, rect, opacity, blend_mode); if (has_xform) { pixman_image_set_transform(src.bitmap.get(), nullptr); @@ -1043,7 +1043,7 @@ void Bitmap::EffectsBlit(int x, int y, int ox, int oy, Bitmap const& src, Rect const& src_rect, Opacity const& opacity, double zoom_x, double zoom_y, double angle, - int waver_depth, double waver_phase) { + int waver_depth, double waver_phase, int blend_mode) { if (opacity.IsTransparent()) { return; } @@ -1054,22 +1054,22 @@ void Bitmap::EffectsBlit(int x, int y, int ox, int oy, if (waver) { WaverBlit(x - ox * zoom_x, y - oy * zoom_y, zoom_x, zoom_y, src, src_rect, - waver_depth, waver_phase, opacity); + waver_depth, waver_phase, opacity, blend_mode); } else if (rotate) { - RotateZoomOpacityBlit(x, y, ox, oy, src, src_rect, angle, zoom_x, zoom_y, opacity); + RotateZoomOpacityBlit(x, y, ox, oy, src, src_rect, angle, zoom_x, zoom_y, opacity, blend_mode); } else if (scale) { - ZoomOpacityBlit(x, y, ox, oy, src, src_rect, zoom_x, zoom_y, opacity); + ZoomOpacityBlit(x, y, ox, oy, src, src_rect, zoom_x, zoom_y, opacity, blend_mode); } else { - Blit(x - ox, y - oy, src, src_rect, opacity); + Blit(x - ox, y - oy, src, src_rect, opacity, blend_mode); } } void Bitmap::RotateZoomOpacityBlit(int x, int y, int ox, int oy, Bitmap const& src, Rect const& src_rect, - double angle, double zoom_x, double zoom_y, Opacity const& opacity) + double angle, double zoom_x, double zoom_y, Opacity const& opacity, int blend_mode) { if (opacity.IsTransparent()) { return; @@ -1101,7 +1101,7 @@ void Bitmap::RotateZoomOpacityBlit(int x, int y, int ox, int oy, auto mask = CreateMask(opacity, src_rect, &inv); - pixman_image_composite32(PIXMAN_OP_OVER, + pixman_image_composite32((pixman_op_t)blend_mode, src_img, mask.get(), bitmap.get(), dst_rect.x, dst_rect.y, dst_rect.x, dst_rect.y, @@ -1114,7 +1114,7 @@ void Bitmap::RotateZoomOpacityBlit(int x, int y, int ox, int oy, void Bitmap::ZoomOpacityBlit(int x, int y, int ox, int oy, Bitmap const& src, Rect const& src_rect, double zoom_x, double zoom_y, - Opacity const& opacity) + Opacity const& opacity, int blend_mode) { if (opacity.IsTransparent()) { return; @@ -1125,10 +1125,14 @@ void Bitmap::ZoomOpacityBlit(int x, int y, int ox, int oy, y - static_cast(std::floor(oy * zoom_y)), static_cast(std::floor(src_rect.width * zoom_x)), static_cast(std::floor(src_rect.height * zoom_y))); - StretchBlit(dst_rect, src, src_rect, opacity); + StretchBlit(dst_rect, src, src_rect, opacity, blend_mode); } -pixman_op_t Bitmap::GetOperator(pixman_image_t* mask) const { +pixman_op_t Bitmap::GetOperator(pixman_image_t* mask, int blend_mode) const { + if (blend_mode >= 0) { + return (pixman_op_t)blend_mode; + } + if (!mask && (!GetTransparent() || GetImageOpacity() == ImageOpacity::Opaque)) { return PIXMAN_OP_SRC; } diff --git a/src/bitmap.h b/src/bitmap.h index bffd8657c3..6b8e33b02f 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -248,8 +248,10 @@ class Bitmap { * @param src source bitmap. * @param src_rect source bitmap rect. * @param opacity opacity for blending with bitmap. + * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image */ - void Blit(int x, int y, Bitmap const& src, Rect const& src_rect, Opacity const& opacity); + void Blit(int x, int y, Bitmap const& src, Rect const& src_rect, + Opacity const& opacity, int blend_mode = -1); /** * Blits source bitmap to this one ignoring alpha (faster) @@ -260,7 +262,8 @@ class Bitmap { * @param src_rect source bitmap rect. * @param opacity opacity for blending with bitmap. */ - void BlitFast(int x, int y, Bitmap const& src, Rect const& src_rect, Opacity const& opacity); + void BlitFast(int x, int y, Bitmap const& src, Rect const& src_rect, + Opacity const& opacity); /** * Blits source bitmap in tiles to this one. @@ -269,8 +272,10 @@ class Bitmap { * @param src source bitmap. * @param dst_rect destination rect. * @param opacity opacity for blending with bitmap. + * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image */ - void TiledBlit(Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, Opacity const& opacity); + void TiledBlit(Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, + Opacity const& opacity, int blend_mode = -1); /** * Blits source bitmap in tiles to this one. @@ -281,8 +286,10 @@ class Bitmap { * @param src source bitmap. * @param dst_rect destination rect. * @param opacity opacity for blending with bitmap. + * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image */ - void TiledBlit(int ox, int oy, Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, Opacity const& opacity); + void TiledBlit(int ox, int oy, Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, + Opacity const& opacity, int blend_mode = -1); /** * Blits source bitmap to this one, making clones across the edges if src crossed a boundary of this. @@ -303,8 +310,10 @@ class Bitmap { * @param src source bitmap. * @param src_rect source bitmap rect. * @param opacity opacity for blending with bitmap. + * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image */ - void StretchBlit(Bitmap const& src, Rect const& src_rect, Opacity const& opacity); + void StretchBlit(Bitmap const& src, Rect const& src_rect, + Opacity const& opacity, int blend_mode = -1); /** * Blits source bitmap stretched to this one. @@ -313,8 +322,10 @@ class Bitmap { * @param src source bitmap. * @param src_rect source bitmap rect. * @param opacity opacity for blending with bitmap. + * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image */ - void StretchBlit(Rect const& dst_rect, Bitmap const& src, Rect const& src_rect, Opacity const& opacity); + void StretchBlit(Rect const& dst_rect, Bitmap const& src, Rect const& src_rect, + Opacity const& opacity, int blend_mode = -1); /** * Blit source bitmap flipped. @@ -326,8 +337,10 @@ class Bitmap { * @param horizontal flip horizontally. * @param vertical flip vertically. * @param opacity opacity to apply. + * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image */ - void FlipBlit(int x, int y, Bitmap const& src, Rect const& src_rect, bool horizontal, bool vertical, Opacity const& opacity); + void FlipBlit(int x, int y, Bitmap const& src, Rect const& src_rect, bool horizontal, bool vertical, + Opacity const& opacity, int blend_mode = -1); /** * Blits source bitmap with waver, zoom, and opacity effects. @@ -341,8 +354,10 @@ class Bitmap { * @param depth wave magnitude. * @param phase wave phase. * @param opacity opacity. + * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image */ - void WaverBlit(int x, int y, double zoom_x, double zoom_y, Bitmap const& src, Rect const& src_rect, int depth, double phase, Opacity const& opacity); + void WaverBlit(int x, int y, double zoom_x, double zoom_y, Bitmap const& src, Rect const& src_rect, int depth, double phase, + Opacity const& opacity, int blend_mode = -1); /** * Blits source bitmap with rotation, zoom, and opacity effects. @@ -357,10 +372,12 @@ class Bitmap { * @param zoom_x x scale factor. * @param zoom_y y scale factor. * @param opacity opacity. + * @param blend_mode Blend mode to use. default: OP_OVER */ void RotateZoomOpacityBlit(int x, int y, int ox, int oy, - Bitmap const& src, Rect const& src_rect, - double angle, double zoom_x, double zoom_y, Opacity const& opacity); + Bitmap const& src, Rect const& src_rect, + double angle, double zoom_x, double zoom_y, + Opacity const& opacity, int blend_mode = PIXMAN_OP_OVER); /** * Blits source bitmap with zoom and opacity scaling. @@ -374,12 +391,12 @@ class Bitmap { * @param zoom_x x scale factor. * @param zoom_y y scale factor. * @param opacity opacity. + * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image */ void ZoomOpacityBlit(int x, int y, int ox, int oy, - Bitmap const& src, Rect const& src_rect, - double zoom_x, double zoom_y, - Opacity const& opacity); - + Bitmap const& src, Rect const& src_rect, + double zoom_x, double zoom_y, + Opacity const& opacity, int blend_mode = -1); /** * Fills entire bitmap with color. @@ -509,12 +526,14 @@ class Bitmap { * @param angle rotation angle. * @param waver_depth wave magnitude. * @param waver_phase wave phase. + * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image */ void EffectsBlit(int x, int y, int ox, int oy, - Bitmap const& src, Rect const& src_rect, - Opacity const& opacity, - double zoom_x, double zoom_y, double angle, - int waver_depth, double waver_phase); + Bitmap const& src, Rect const& src_rect, + Opacity const& opacity, + double zoom_x, double zoom_y, double angle, + int waver_depth, double waver_phase, + int blend_mode = -1); static DynamicFormat ChooseFormat(const DynamicFormat& format); static void SetFormat(const DynamicFormat& format); @@ -566,7 +585,15 @@ class Bitmap { static pixman_format_code_t find_format(const DynamicFormat& format); - pixman_op_t GetOperator(pixman_image_t* mask = nullptr) const; + /* + * Determines the fastest operator for the operation. + * When a blend_mode is specified the blend mode is used. + * + * @param mask Image mask + * @param blend_mode When >= 0: Force this blend mode as operator + * @return blend mode + */ + pixman_op_t GetOperator(pixman_image_t* mask = nullptr, int blend_mode = -1) const; bool read_only = false; }; diff --git a/src/sprite.cpp b/src/sprite.cpp index c612b4c65d..cc50282195 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -65,9 +65,9 @@ void Sprite::BlitScreenIntern(Bitmap& dst, Bitmap const& draw_bitmap, Rect const double zoom_y = zoom_y_effect; dst.EffectsBlit(x, y, ox, oy, draw_bitmap, src_rect, - Opacity(opacity_top_effect, opacity_bottom_effect, bush_effect), - zoom_x, zoom_y, angle_effect, - waver_effect_depth, waver_effect_phase); + Opacity(opacity_top_effect, opacity_bottom_effect, bush_effect), + zoom_x, zoom_y, angle_effect, + waver_effect_depth, waver_effect_phase, blend_type_effect); } BitmapRef Sprite::Refresh(Rect& rect) { diff --git a/src/sprite.h b/src/sprite.h index 2690d026da..6129965bdb 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -119,7 +119,7 @@ class Sprite : public Drawable { double zoom_x_effect = 1.0; double zoom_y_effect = 1.0; double angle_effect = 0.0; - int blend_type_effect; + int blend_type_effect = -1; Color blend_color_effect; int waver_effect_depth = 0; double waver_effect_phase = 0.0; From 336dde25d88fb311a8b68353e41904642934bc83 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Wed, 1 Sep 2021 17:11:32 +0200 Subject: [PATCH 2/9] Maniac: Support some "Show Picture" enhancements - Blend Mode - Flip X/Y The way how this is stored in the savefile is incompatible. Maniac Patch uses the upper bits of "bottom_transparency" here. --- src/game_interpreter.cpp | 22 +++++++++++++++++++--- src/game_pictures.cpp | 11 +++++++++-- src/game_pictures.h | 4 ++++ src/sprite_picture.cpp | 6 ++++-- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index ef41ecca92..fd0e25abfc 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -2639,8 +2639,9 @@ bool Game_Interpreter::CommandShowPicture(lcf::rpg::EventCommand const& com) { / Game_Pictures::ShowParams params = {}; params.name = ToString(com.string); - params.position_x = ValueOrVariable(com.parameters[1], com.parameters[2]); - params.position_y = ValueOrVariable(com.parameters[1], com.parameters[3]); + // Maniac Patch uses the upper bits for X/Y origin, mask it away + params.position_x = ValueOrVariable(com.parameters[1] & 0xFF, com.parameters[2]); + params.position_y = ValueOrVariable(com.parameters[1] & 0xFF, com.parameters[3]); params.fixed_to_map = com.parameters[4] > 0; params.magnify = com.parameters[5]; params.use_transparent_color = com.parameters[7] > 0; @@ -2658,7 +2659,8 @@ bool Game_Interpreter::CommandShowPicture(lcf::rpg::EventCommand const& com) { / // RPG2k3 sets this chunk. Versions < 1.12 let you specify separate top and bottom // transparency. >= 1.12 Editor only let you set one transparency field but it affects // both chunks here. - params.bottom_trans = com.parameters[14]; + // Maniac Patch uses the upper bits for flags, mask it away + params.bottom_trans = com.parameters[14] & 0xFF; } else if (Player::IsRPG2k3() && !Player::IsRPG2k3E()) { // Corner case when 2k maps are used in 2k3 (pre-1.10) and don't contain this chunk params.bottom_trans = params.top_trans; @@ -2694,6 +2696,20 @@ bool Game_Interpreter::CommandShowPicture(lcf::rpg::EventCommand const& com) { / params.map_layer = com.parameters[27]; params.battle_layer = com.parameters[28]; params.flags = com.parameters[29]; + + if (Player::IsPatchManiac()) { + int flags = com.parameters[14] >> 8; + int blend_mode = flags & 3; + if (blend_mode == 1) { + params.blend_mode = PIXMAN_OP_MULTIPLY; + } else if (blend_mode == 2) { + params.blend_mode = PIXMAN_OP_ADD; + } else if (blend_mode == 3) { + params.blend_mode = PIXMAN_OP_OVERLAY; + } + params.flip_x = (flags & 16) == 16; + params.flip_y = (flags & 32) == 32; + } } PicPointerPatch::AdjustShowParams(pic_id, params); diff --git a/src/game_pictures.cpp b/src/game_pictures.cpp index 44820ff96b..948e64652c 100644 --- a/src/game_pictures.cpp +++ b/src/game_pictures.cpp @@ -210,6 +210,8 @@ bool Game_Pictures::Picture::Show(const ShowParams& params) { const auto num_frames = NumSpriteSheetFrames(); + bool result = true; + // If an invalid frame is specified and no animation, skip loading picture data. if (num_frames > 0 && data.spritesheet_speed == 0 @@ -218,10 +220,15 @@ bool Game_Pictures::Picture::Show(const ShowParams& params) { if (sprite) { sprite->SetBitmap(nullptr); } - return false; + result = false; } - return true; + // Extensions + data.easyrpg_flip |= params.flip_x ? lcf::rpg::SavePicture::EasyRpgFlip_x : 0; + data.easyrpg_flip |= params.flip_y ? lcf::rpg::SavePicture::EasyRpgFlip_y : 0; + data.easyrpg_blend_mode = params.blend_mode; + + return result; } void Game_Pictures::Show(int id, const ShowParams& params) { diff --git a/src/game_pictures.h b/src/game_pictures.h index 5dd4f09a02..59b03aabbf 100644 --- a/src/game_pictures.h +++ b/src/game_pictures.h @@ -69,6 +69,10 @@ class Game_Pictures { bool spritesheet_play_once = false; bool use_transparent_color = false; bool fixed_to_map = false; + // Extensions + bool flip_x = false; + bool flip_y = false; + int blend_mode = -1; }; struct MoveParams : Params { diff --git a/src/sprite_picture.cpp b/src/sprite_picture.cpp index 2402bec7e7..a558f07a6d 100644 --- a/src/sprite_picture.cpp +++ b/src/sprite_picture.cpp @@ -142,7 +142,9 @@ void Sprite_Picture::Draw(Bitmap& dst) { SetFlashEffect(Main_Data::game_screen->GetFlashColor()); } + SetFlipX((data.easyrpg_flip & lcf::rpg::SavePicture::EasyRpgFlip_x) == lcf::rpg::SavePicture::EasyRpgFlip_x); + SetFlipY((data.easyrpg_flip & lcf::rpg::SavePicture::EasyRpgFlip_y) == lcf::rpg::SavePicture::EasyRpgFlip_y); + SetBlendType(data.easyrpg_blend_mode); + Sprite::Draw(dst); } - - From a460de60a488ae20d1f98168f9b6474a5b62ef6f Mon Sep 17 00:00:00 2001 From: Ghabry Date: Wed, 1 Sep 2021 17:26:00 +0200 Subject: [PATCH 3/9] Maniac: Support some "Move Picture" enhancements - Blend Mode - Flip X/Y The way how this is stored in the savefile is incompatible. Maniac Patch uses the upper bits of "bottom_transparency" here. --- src/game_interpreter.cpp | 19 +++++++++++++++++-- src/game_pictures.cpp | 6 +++++- src/game_pictures.h | 8 ++++---- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index fd0e25abfc..a1622d88cf 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -2740,8 +2740,9 @@ bool Game_Interpreter::CommandMovePicture(lcf::rpg::EventCommand const& com) { / int pic_id = com.parameters[0]; Game_Pictures::MoveParams params; - params.position_x = ValueOrVariable(com.parameters[1], com.parameters[2]); - params.position_y = ValueOrVariable(com.parameters[1], com.parameters[3]); + // Maniac Patch uses the upper bits for X/Y origin, mask it away + params.position_x = ValueOrVariable(com.parameters[1] & 0xFF, com.parameters[2]); + params.position_y = ValueOrVariable(com.parameters[1] & 0xFF, com.parameters[3]); params.magnify = com.parameters[5]; params.top_trans = com.parameters[6]; params.red = com.parameters[8]; @@ -2769,6 +2770,20 @@ bool Game_Interpreter::CommandMovePicture(lcf::rpg::EventCommand const& com) { / // RPG2k and RPG2k3 1.10 do not support this option params.bottom_trans = params.top_trans; + + if (Player::IsPatchManiac()) { + int flags = com.parameters[16] >> 8; + int blend_mode = flags & 3; + if (blend_mode == 1) { + params.blend_mode = PIXMAN_OP_MULTIPLY; + } else if (blend_mode == 2) { + params.blend_mode = PIXMAN_OP_ADD; + } else if (blend_mode == 3) { + params.blend_mode = PIXMAN_OP_OVERLAY; + } + params.flip_x = (flags & 16) == 16; + params.flip_y = (flags & 32) == 32; + } } else { // Corner case when 2k maps are used in 2k3 (pre-1.10) and don't contain this chunk params.bottom_trans = param_size > 16 ? com.parameters[16] : params.top_trans; diff --git a/src/game_pictures.cpp b/src/game_pictures.cpp index 948e64652c..f03b337fa2 100644 --- a/src/game_pictures.cpp +++ b/src/game_pictures.cpp @@ -224,7 +224,7 @@ bool Game_Pictures::Picture::Show(const ShowParams& params) { } // Extensions - data.easyrpg_flip |= params.flip_x ? lcf::rpg::SavePicture::EasyRpgFlip_x : 0; + data.easyrpg_flip = params.flip_x ? lcf::rpg::SavePicture::EasyRpgFlip_x : 0; data.easyrpg_flip |= params.flip_y ? lcf::rpg::SavePicture::EasyRpgFlip_y : 0; data.easyrpg_blend_mode = params.blend_mode; @@ -284,6 +284,10 @@ void Game_Pictures::Picture::Move(const MoveParams& params) { data.current_effect_power = params.effect_power; data.finish_effect_power = params.effect_power; } + + data.easyrpg_flip = params.flip_x ? lcf::rpg::SavePicture::EasyRpgFlip_x : 0; + data.easyrpg_flip |= params.flip_y ? lcf::rpg::SavePicture::EasyRpgFlip_y : 0; + data.easyrpg_blend_mode = params.blend_mode; } void Game_Pictures::Move(int id, const MoveParams& params) { diff --git a/src/game_pictures.h b/src/game_pictures.h index 59b03aabbf..7023802dfe 100644 --- a/src/game_pictures.h +++ b/src/game_pictures.h @@ -54,6 +54,10 @@ class Game_Pictures { int saturation = 100; int effect_mode = 0; int effect_power = 0; + // Extensions + bool flip_x = false; + bool flip_y = false; + int blend_mode = -1; }; struct ShowParams : Params { std::string name; @@ -69,10 +73,6 @@ class Game_Pictures { bool spritesheet_play_once = false; bool use_transparent_color = false; bool fixed_to_map = false; - // Extensions - bool flip_x = false; - bool flip_y = false; - int blend_mode = -1; }; struct MoveParams : Params { From 4392df8cee52f2af7b40fa5c50bd3657464bec18 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Wed, 1 Sep 2021 18:34:45 +0200 Subject: [PATCH 4/9] Add an additional abstraction between pixman_op_t and the Blend Mode --- src/bitmap.cpp | 61 +++++++++++++++++++++++++++++++--------- src/bitmap.h | 60 +++++++++++++++++++++++++-------------- src/game_interpreter.cpp | 12 ++++---- src/game_pictures.h | 2 +- src/sprite.cpp | 2 +- src/sprite.h | 2 +- 6 files changed, 95 insertions(+), 44 deletions(-) diff --git a/src/bitmap.cpp b/src/bitmap.cpp index 5264efd9fb..cb3cb573b5 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -569,7 +569,7 @@ namespace { } } // anonymous namespace -void Bitmap::Blit(int x, int y, Bitmap const& src, Rect const& src_rect, Opacity const& opacity, int blend_mode) { +void Bitmap::Blit(int x, int y, Bitmap const& src, Rect const& src_rect, Opacity const& opacity, Bitmap::BlendMode blend_mode) { if (opacity.IsTransparent()) { return; } @@ -605,11 +605,11 @@ PixmanImagePtr Bitmap::GetSubimage(Bitmap const& src, const Rect& src_rect) { (uint32_t*) pixels, src.pitch()) }; } -void Bitmap::TiledBlit(Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, Opacity const& opacity, int blend_mode) { +void Bitmap::TiledBlit(Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, Opacity const& opacity, Bitmap::BlendMode blend_mode) { TiledBlit(0, 0, src_rect, src, dst_rect, opacity, blend_mode); } -void Bitmap::TiledBlit(int ox, int oy, Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, Opacity const& opacity, int blend_mode) { +void Bitmap::TiledBlit(int ox, int oy, Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, Opacity const& opacity, Bitmap::BlendMode blend_mode) { if (opacity.IsTransparent()) { return; } @@ -633,11 +633,11 @@ void Bitmap::TiledBlit(int ox, int oy, Rect const& src_rect, Bitmap const& src, dst_rect.width, dst_rect.height); } -void Bitmap::StretchBlit(Bitmap const& src, Rect const& src_rect, Opacity const& opacity, int blend_mode) { +void Bitmap::StretchBlit(Bitmap const& src, Rect const& src_rect, Opacity const& opacity, Bitmap::BlendMode blend_mode) { StretchBlit(GetRect(), src, src_rect, opacity, blend_mode); } -void Bitmap::StretchBlit(Rect const& dst_rect, Bitmap const& src, Rect const& src_rect, Opacity const& opacity, int blend_mode) { +void Bitmap::StretchBlit(Rect const& dst_rect, Bitmap const& src, Rect const& src_rect, Opacity const& opacity, Bitmap::BlendMode blend_mode) { if (opacity.IsTransparent()) { return; } @@ -661,7 +661,7 @@ void Bitmap::StretchBlit(Rect const& dst_rect, Bitmap const& src, Rect const& sr pixman_image_set_transform(src.bitmap.get(), nullptr); } -void Bitmap::WaverBlit(int x, int y, double zoom_x, double zoom_y, Bitmap const& src, Rect const& src_rect, int depth, double phase, Opacity const& opacity, int blend_mode) { +void Bitmap::WaverBlit(int x, int y, double zoom_x, double zoom_y, Bitmap const& src, Rect const& src_rect, int depth, double phase, Opacity const& opacity, Bitmap::BlendMode blend_mode) { if (opacity.IsTransparent()) { return; } @@ -946,7 +946,7 @@ void Bitmap::BlendBlit(int x, int y, Bitmap const& src, Rect const& src_rect, co src_rect.width, src_rect.height); } -void Bitmap::FlipBlit(int x, int y, Bitmap const& src, Rect const& src_rect, bool horizontal, bool vertical, Opacity const& opacity, int blend_mode) { +void Bitmap::FlipBlit(int x, int y, Bitmap const& src, Rect const& src_rect, bool horizontal, bool vertical, Opacity const& opacity, Bitmap::BlendMode blend_mode) { if (opacity.IsTransparent()) { return; } @@ -1043,7 +1043,7 @@ void Bitmap::EffectsBlit(int x, int y, int ox, int oy, Bitmap const& src, Rect const& src_rect, Opacity const& opacity, double zoom_x, double zoom_y, double angle, - int waver_depth, double waver_phase, int blend_mode) { + int waver_depth, double waver_phase, Bitmap::BlendMode blend_mode) { if (opacity.IsTransparent()) { return; } @@ -1069,7 +1069,7 @@ void Bitmap::EffectsBlit(int x, int y, int ox, int oy, void Bitmap::RotateZoomOpacityBlit(int x, int y, int ox, int oy, Bitmap const& src, Rect const& src_rect, - double angle, double zoom_x, double zoom_y, Opacity const& opacity, int blend_mode) + double angle, double zoom_x, double zoom_y, Opacity const& opacity, Bitmap::BlendMode blend_mode) { if (opacity.IsTransparent()) { return; @@ -1101,7 +1101,7 @@ void Bitmap::RotateZoomOpacityBlit(int x, int y, int ox, int oy, auto mask = CreateMask(opacity, src_rect, &inv); - pixman_image_composite32((pixman_op_t)blend_mode, + pixman_image_composite32(GetOperator(mask.get(), blend_mode), src_img, mask.get(), bitmap.get(), dst_rect.x, dst_rect.y, dst_rect.x, dst_rect.y, @@ -1114,7 +1114,7 @@ void Bitmap::RotateZoomOpacityBlit(int x, int y, int ox, int oy, void Bitmap::ZoomOpacityBlit(int x, int y, int ox, int oy, Bitmap const& src, Rect const& src_rect, double zoom_x, double zoom_y, - Opacity const& opacity, int blend_mode) + Opacity const& opacity, Bitmap::BlendMode blend_mode) { if (opacity.IsTransparent()) { return; @@ -1128,9 +1128,42 @@ void Bitmap::ZoomOpacityBlit(int x, int y, int ox, int oy, StretchBlit(dst_rect, src, src_rect, opacity, blend_mode); } -pixman_op_t Bitmap::GetOperator(pixman_image_t* mask, int blend_mode) const { - if (blend_mode >= 0) { - return (pixman_op_t)blend_mode; +pixman_op_t Bitmap::GetOperator(pixman_image_t* mask, Bitmap::BlendMode blend_mode) const { + if (blend_mode != BlendMode::Default) { + switch (blend_mode) { + case BlendMode::Normal: + return PIXMAN_OP_OVER; + case BlendMode::NormalWithoutAlpha: + return PIXMAN_OP_SRC; + case BlendMode::XOR: + return PIXMAN_OP_XOR; + case BlendMode::Additive: + return PIXMAN_OP_ADD; + case BlendMode::Multiply: + return PIXMAN_OP_MULTIPLY; + case BlendMode::Overlay: + return PIXMAN_OP_OVERLAY; + case BlendMode::Saturate: + return PIXMAN_OP_SATURATE; + case BlendMode::Darken: + return PIXMAN_OP_DARKEN; + case BlendMode::Lighten: + return PIXMAN_OP_LIGHTEN; + case BlendMode::ColorDodge: + return PIXMAN_OP_COLOR_DODGE; + case BlendMode::ColorBurn: + return PIXMAN_OP_COLOR_BURN; + case BlendMode::Difference: + return PIXMAN_OP_DIFFERENCE; + case BlendMode::Exclusion: + return PIXMAN_OP_EXCLUSION; + case BlendMode::SoftLight: + return PIXMAN_OP_SOFT_LIGHT; + case BlendMode::HardLight: + return PIXMAN_OP_HARD_LIGHT; + default: + return PIXMAN_OP_CLEAR; + } } if (!mask && (!GetTransparent() || GetImageOpacity() == ImageOpacity::Opaque)) { diff --git a/src/bitmap.h b/src/bitmap.h index 6b8e33b02f..f13404b034 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -153,6 +153,24 @@ class Bitmap { Flag_ReadOnly = 1 << 16 }; + enum class BlendMode { + Default, // SRC or OVER depending on the image + Normal, // OP_OVER + NormalWithoutAlpha, // OP_SRC + XOR, + Additive, + Multiply, + Overlay, + Saturate, + Darken, + Lighten, + ColorDodge, + ColorBurn, + Difference, + Exclusion, + SoftLight, + HardLight + }; /** * Provides opacity information about the image. @@ -248,10 +266,10 @@ class Bitmap { * @param src source bitmap. * @param src_rect source bitmap rect. * @param opacity opacity for blending with bitmap. - * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image + * @param blend_mode Blend mode to use. */ void Blit(int x, int y, Bitmap const& src, Rect const& src_rect, - Opacity const& opacity, int blend_mode = -1); + Opacity const& opacity, BlendMode blend_mode = BlendMode::Default); /** * Blits source bitmap to this one ignoring alpha (faster) @@ -272,10 +290,10 @@ class Bitmap { * @param src source bitmap. * @param dst_rect destination rect. * @param opacity opacity for blending with bitmap. - * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image + * @param blend_mode Blend mode to use. */ void TiledBlit(Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, - Opacity const& opacity, int blend_mode = -1); + Opacity const& opacity, BlendMode blend_mode = BlendMode::Default); /** * Blits source bitmap in tiles to this one. @@ -286,10 +304,10 @@ class Bitmap { * @param src source bitmap. * @param dst_rect destination rect. * @param opacity opacity for blending with bitmap. - * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image + * @param blend_mode Blend mode to use. */ void TiledBlit(int ox, int oy, Rect const& src_rect, Bitmap const& src, Rect const& dst_rect, - Opacity const& opacity, int blend_mode = -1); + Opacity const& opacity, BlendMode blend_mode = BlendMode::Default); /** * Blits source bitmap to this one, making clones across the edges if src crossed a boundary of this. @@ -310,10 +328,10 @@ class Bitmap { * @param src source bitmap. * @param src_rect source bitmap rect. * @param opacity opacity for blending with bitmap. - * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image + * @param blend_mode Blend mode to use. */ void StretchBlit(Bitmap const& src, Rect const& src_rect, - Opacity const& opacity, int blend_mode = -1); + Opacity const& opacity, BlendMode blend_mode = BlendMode::Default); /** * Blits source bitmap stretched to this one. @@ -322,10 +340,10 @@ class Bitmap { * @param src source bitmap. * @param src_rect source bitmap rect. * @param opacity opacity for blending with bitmap. - * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image + * @param blend_mode Blend mode to use. */ void StretchBlit(Rect const& dst_rect, Bitmap const& src, Rect const& src_rect, - Opacity const& opacity, int blend_mode = -1); + Opacity const& opacity, BlendMode blend_mode = BlendMode::Default); /** * Blit source bitmap flipped. @@ -337,10 +355,10 @@ class Bitmap { * @param horizontal flip horizontally. * @param vertical flip vertically. * @param opacity opacity to apply. - * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image + * @param blend_mode Blend mode to use. */ void FlipBlit(int x, int y, Bitmap const& src, Rect const& src_rect, bool horizontal, bool vertical, - Opacity const& opacity, int blend_mode = -1); + Opacity const& opacity, BlendMode blend_mode = BlendMode::Default); /** * Blits source bitmap with waver, zoom, and opacity effects. @@ -354,10 +372,10 @@ class Bitmap { * @param depth wave magnitude. * @param phase wave phase. * @param opacity opacity. - * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image + * @param blend_mode Blend mode to use. */ void WaverBlit(int x, int y, double zoom_x, double zoom_y, Bitmap const& src, Rect const& src_rect, int depth, double phase, - Opacity const& opacity, int blend_mode = -1); + Opacity const& opacity, BlendMode blend_mode = BlendMode::Default); /** * Blits source bitmap with rotation, zoom, and opacity effects. @@ -372,12 +390,12 @@ class Bitmap { * @param zoom_x x scale factor. * @param zoom_y y scale factor. * @param opacity opacity. - * @param blend_mode Blend mode to use. default: OP_OVER + * @param blend_mode Blend mode to use. */ void RotateZoomOpacityBlit(int x, int y, int ox, int oy, Bitmap const& src, Rect const& src_rect, double angle, double zoom_x, double zoom_y, - Opacity const& opacity, int blend_mode = PIXMAN_OP_OVER); + Opacity const& opacity, BlendMode blend_mode = BlendMode::Normal); /** * Blits source bitmap with zoom and opacity scaling. @@ -391,12 +409,12 @@ class Bitmap { * @param zoom_x x scale factor. * @param zoom_y y scale factor. * @param opacity opacity. - * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image + * @param blend_mode Blend mode to use. */ void ZoomOpacityBlit(int x, int y, int ox, int oy, Bitmap const& src, Rect const& src_rect, double zoom_x, double zoom_y, - Opacity const& opacity, int blend_mode = -1); + Opacity const& opacity, BlendMode blend_mode = BlendMode::Default); /** * Fills entire bitmap with color. @@ -526,14 +544,14 @@ class Bitmap { * @param angle rotation angle. * @param waver_depth wave magnitude. * @param waver_phase wave phase. - * @param blend_mode Blend mode to use. default: OP_SRC/OP_OVER; depends on the image + * @param blend_mode Blend mode to use. */ void EffectsBlit(int x, int y, int ox, int oy, Bitmap const& src, Rect const& src_rect, Opacity const& opacity, double zoom_x, double zoom_y, double angle, int waver_depth, double waver_phase, - int blend_mode = -1); + BlendMode blend_mode = BlendMode::Default); static DynamicFormat ChooseFormat(const DynamicFormat& format); static void SetFormat(const DynamicFormat& format); @@ -593,7 +611,7 @@ class Bitmap { * @param blend_mode When >= 0: Force this blend mode as operator * @return blend mode */ - pixman_op_t GetOperator(pixman_image_t* mask = nullptr, int blend_mode = -1) const; + pixman_op_t GetOperator(pixman_image_t* mask = nullptr, BlendMode blend_mode = BlendMode::Default) const; bool read_only = false; }; diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index a1622d88cf..6616bbe7dd 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -2701,11 +2701,11 @@ bool Game_Interpreter::CommandShowPicture(lcf::rpg::EventCommand const& com) { / int flags = com.parameters[14] >> 8; int blend_mode = flags & 3; if (blend_mode == 1) { - params.blend_mode = PIXMAN_OP_MULTIPLY; + params.blend_mode = (int)Bitmap::BlendMode::Multiply; } else if (blend_mode == 2) { - params.blend_mode = PIXMAN_OP_ADD; + params.blend_mode = (int)Bitmap::BlendMode::Additive; } else if (blend_mode == 3) { - params.blend_mode = PIXMAN_OP_OVERLAY; + params.blend_mode = (int)Bitmap::BlendMode::Overlay; } params.flip_x = (flags & 16) == 16; params.flip_y = (flags & 32) == 32; @@ -2775,11 +2775,11 @@ bool Game_Interpreter::CommandMovePicture(lcf::rpg::EventCommand const& com) { / int flags = com.parameters[16] >> 8; int blend_mode = flags & 3; if (blend_mode == 1) { - params.blend_mode = PIXMAN_OP_MULTIPLY; + params.blend_mode = (int)Bitmap::BlendMode::Multiply; } else if (blend_mode == 2) { - params.blend_mode = PIXMAN_OP_ADD; + params.blend_mode = (int)Bitmap::BlendMode::Additive; } else if (blend_mode == 3) { - params.blend_mode = PIXMAN_OP_OVERLAY; + params.blend_mode = (int)Bitmap::BlendMode::Overlay; } params.flip_x = (flags & 16) == 16; params.flip_y = (flags & 32) == 32; diff --git a/src/game_pictures.h b/src/game_pictures.h index 7023802dfe..114f421e1a 100644 --- a/src/game_pictures.h +++ b/src/game_pictures.h @@ -57,7 +57,7 @@ class Game_Pictures { // Extensions bool flip_x = false; bool flip_y = false; - int blend_mode = -1; + int blend_mode = 0; }; struct ShowParams : Params { std::string name; diff --git a/src/sprite.cpp b/src/sprite.cpp index cc50282195..16203e9fc1 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -67,7 +67,7 @@ void Sprite::BlitScreenIntern(Bitmap& dst, Bitmap const& draw_bitmap, Rect const dst.EffectsBlit(x, y, ox, oy, draw_bitmap, src_rect, Opacity(opacity_top_effect, opacity_bottom_effect, bush_effect), zoom_x, zoom_y, angle_effect, - waver_effect_depth, waver_effect_phase, blend_type_effect); + waver_effect_depth, waver_effect_phase, static_cast(blend_type_effect)); } BitmapRef Sprite::Refresh(Rect& rect) { diff --git a/src/sprite.h b/src/sprite.h index 6129965bdb..3e0857f8d3 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -119,7 +119,7 @@ class Sprite : public Drawable { double zoom_x_effect = 1.0; double zoom_y_effect = 1.0; double angle_effect = 0.0; - int blend_type_effect = -1; + int blend_type_effect = 0; Color blend_color_effect; int waver_effect_depth = 0; double waver_effect_phase = 0.0; From 077e4e837652730b9cc2e940327bfc0320ab5888 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Thu, 9 Sep 2021 20:37:00 +0200 Subject: [PATCH 5/9] Bitmap: Remember the filename, useful for debugging purposes --- src/bitmap.cpp | 2 ++ src/bitmap.h | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/bitmap.cpp b/src/bitmap.cpp index cb3cb573b5..4623aa7127 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -130,6 +130,8 @@ Bitmap::Bitmap(Filesystem_Stream::InputStream stream, bool transparent, uint32_t ConvertImage(w, h, pixels, transparent); CheckPixels(flags); + + filename = ToString(stream.GetName()); } Bitmap::Bitmap(const uint8_t* data, unsigned bytes, bool transparent, uint32_t flags) { diff --git a/src/bitmap.h b/src/bitmap.h index f13404b034..681a520f64 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -215,6 +215,14 @@ class Bitmap { */ Color GetShadowColor() const; + /** + * Gets the filename this bitmap was loaded from. + * This will be empty when the origin was not a file. + * + * @return filename + */ + StringView GetFilename() const; + void CheckPixels(uint32_t flags); /** @@ -578,6 +586,8 @@ class Bitmap { TileOpacity tile_opacity; Color bg_color, sh_color; + std::string filename; + /** Bitmap data. */ PixmanImagePtr bitmap; pixman_format_code_t pixman_format; @@ -647,4 +657,8 @@ inline bool Bitmap::GetTransparent() const { return format.alpha_type != PF::NoAlpha; } +inline StringView Bitmap::GetFilename() const { + return filename; +} + #endif From 71633d8310040a56c167aa67777334c97e67836f Mon Sep 17 00:00:00 2001 From: Ghabry Date: Thu, 9 Sep 2021 21:35:59 +0200 Subject: [PATCH 6/9] Maniac: Warn about unimplemented Show/Move Picture features --- src/game_interpreter.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 6616bbe7dd..99256789d9 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -2709,6 +2709,15 @@ bool Game_Interpreter::CommandShowPicture(lcf::rpg::EventCommand const& com) { / } params.flip_x = (flags & 16) == 16; params.flip_y = (flags & 32) == 32; + + if ((com.parameters[1] >> 8) != 0) { + Output::Warning("Maniac ShowPicture: X/Y origin not supported"); + } + + if (params.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) { + Output::Warning("Maniac ShowPicture: Fixed angle not supported"); + params.effect_mode = lcf::rpg::SavePicture::Effect_none; + } } } @@ -2783,6 +2792,15 @@ bool Game_Interpreter::CommandMovePicture(lcf::rpg::EventCommand const& com) { / } params.flip_x = (flags & 16) == 16; params.flip_y = (flags & 32) == 32; + + if ((com.parameters[1] >> 8) != 0) { + Output::Warning("Maniac MovePicture: X/Y origin not supported"); + } + + if (params.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) { + Output::Warning("Maniac MovePicture: Fixed angle not supported"); + params.effect_mode = lcf::rpg::SavePicture::Effect_none; + } } } else { // Corner case when 2k maps are used in 2k3 (pre-1.10) and don't contain this chunk From 56475aeb522911f30bfb81a6f18eef19561c4f9f Mon Sep 17 00:00:00 2001 From: Ghabry Date: Sun, 12 Sep 2021 11:58:25 +0200 Subject: [PATCH 7/9] Simplify lookup functions --- src/game_interpreter.cpp | 8 ++++---- src/game_switches.h | 5 +++++ src/game_variables.h | 6 ++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 99256789d9..c4d1a32051 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -1691,13 +1691,13 @@ int Game_Interpreter::ValueOrVariable(int mode, int val) { // For simplicity it is enabled for all here if (mode == 2) { // Variable indirect - return Main_Data::game_variables->Get(Main_Data::game_variables->Get(val)); + return Main_Data::game_variables->GetIndirect(val); } else if (mode == 3) { // Switch (F = 0, T = 1) - return Main_Data::game_switches->Get(val) ? 1 : 0; + return Main_Data::game_switches->GetInt(val); } else if (mode == 4) { - // Switch through Variable indirect - return Main_Data::game_switches->Get(Main_Data::game_variables->Get(val)) ? 1 : 0; + // Switch through Variable (F = 0, T = 1) + return Main_Data::game_switches->GetInt(Main_Data::game_variables->Get(val)); } } return -1; diff --git a/src/game_switches.h b/src/game_switches.h index d7fad48e07..a8bb9446f7 100644 --- a/src/game_switches.h +++ b/src/game_switches.h @@ -39,6 +39,7 @@ class Game_Switches { const Switches_t& GetData() const; bool Get(int switch_id) const; + int GetInt(int switch_id) const; bool Set(int switch_id, bool value); void SetRange(int first_id, int last_id, bool value); @@ -94,6 +95,10 @@ inline bool Game_Switches::Get(int switch_id) const { return _switches[switch_id - 1]; } +inline int Game_Switches::GetInt(int switch_id) const { + return Get(switch_id) ? 1 : 0; +} + inline void Game_Switches::SetWarning(int w) { _warnings = w; } diff --git a/src/game_variables.h b/src/game_variables.h index f7dbf77bed..8aef628d60 100644 --- a/src/game_variables.h +++ b/src/game_variables.h @@ -44,6 +44,7 @@ class Game_Variables { const Variables_t& GetData() const; Var_t Get(int variable_id) const; + Var_t GetIndirect(int variable_id) const; Var_t Set(int variable_id, Var_t value); Var_t Add(int variable_id, Var_t value); @@ -140,6 +141,11 @@ inline Game_Variables::Var_t Game_Variables::Get(int variable_id) const { return _variables[variable_id - 1]; } +inline Game_Variables::Var_t Game_Variables::GetIndirect(int variable_id) const { + auto val_indirect = Get(variable_id); + return Get(static_cast(val_indirect)); +} + inline void Game_Variables::SetWarning(int w) { _warnings = w; } From 5094f936b175e3c771e9c83ee89bdc197b2f89d3 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Sun, 12 Sep 2021 12:00:43 +0200 Subject: [PATCH 8/9] Maniac: Implement Erase Picture enhancements --- src/game_interpreter.cpp | 44 +++++++++++++++++++++++++++++++++------- src/game_pictures.cpp | 6 ++++++ src/game_pictures.h | 1 + 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index c4d1a32051..87fd9fa3dc 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -2839,15 +2839,45 @@ bool Game_Interpreter::CommandErasePicture(lcf::rpg::EventCommand const& com) { // Handling of RPG2k3 1.12 chunks int id_type = com.parameters[1]; - int max; - if (id_type < 2) { - pic_id = ValueOrVariable(id_type, pic_id); - max = pic_id; - } else { - max = com.parameters[2]; + int pic_id_max; + switch (id_type) { + case 1: + // Erase single picture referenced by variable + pic_id = Main_Data::game_variables->Get(pic_id); + pic_id_max = pic_id; + break; + case 2: + // Erase [Arg0, Arg2] + pic_id_max = com.parameters[2]; + break; + case 3: + // Erase [V[Arg0], V[Arg2]] + if (!Player::IsPatchManiac()) { + return true; + } + pic_id = Main_Data::game_variables->Get(pic_id); + pic_id_max = Main_Data::game_variables->Get(com.parameters[2]); + break; + case 4: + // Erase single picture referenced by variable indirect + if (!Player::IsPatchManiac()) { + return true; + } + pic_id = Main_Data::game_variables->GetIndirect(pic_id); + pic_id_max = pic_id; + break; + case 5: + // Erase all pictures + if (!Player::IsPatchManiac()) { + return true; + } + Main_Data::game_pictures->EraseAll(); + return true; + default: + return true; } - for (int i = pic_id; i <= max; ++i) { + for (int i = pic_id; i <= pic_id_max; ++i) { if (i <= 0) { Output::Error("ErasePicture: Requested invalid picture id ({})", i); } diff --git a/src/game_pictures.cpp b/src/game_pictures.cpp index f03b337fa2..9196b8e34f 100644 --- a/src/game_pictures.cpp +++ b/src/game_pictures.cpp @@ -310,6 +310,12 @@ void Game_Pictures::Erase(int id) { } } +void Game_Pictures::EraseAll() { + for (auto& pic: pictures) { + pic.Erase(); + } +} + bool Game_Pictures::Picture::Exists() const { // Incompatible with the Yume2kki edge-case that uses empty filenames return !data.name.empty(); diff --git a/src/game_pictures.h b/src/game_pictures.h index 114f421e1a..5b1fefdb95 100644 --- a/src/game_pictures.h +++ b/src/game_pictures.h @@ -82,6 +82,7 @@ class Game_Pictures { void Show(int id, const ShowParams& params); void Move(int id, const MoveParams& params); void Erase(int id); + void EraseAll(); void Update(bool is_battle); From 602a70f9a78dd7a7adfec12acc83e9451e3a858c Mon Sep 17 00:00:00 2001 From: Ghabry Date: Sun, 12 Sep 2021 12:11:26 +0200 Subject: [PATCH 9/9] Maniac: Warn about unimplemented Loop enhancements --- src/game_interpreter.cpp | 12 +++++++++++- src/game_interpreter.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 87fd9fa3dc..77feb1bb66 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -730,7 +730,7 @@ bool Game_Interpreter::ExecuteCommand() { case Cmd::JumpToLabel: return CommandJumpToLabel(com); case Cmd::Loop: - return true; + return CommandLoop(com); case Cmd::BreakLoop: return CommandBreakLoop(com); case Cmd::EndLoop: @@ -3501,6 +3501,16 @@ bool Game_Interpreter::CommandJumpToLabel(lcf::rpg::EventCommand const& com) { / return true; } +bool Game_Interpreter::CommandLoop(lcf::rpg::EventCommand const& com) { // code 12210 + if (!Player::IsPatchManiac() || com.parameters.empty() || com.parameters[0] == 0) { + // Infinite Loop + return true; + } + + Output::Warning("Maniac CommandLoop: Conditional loops unsupported"); + return true; +} + bool Game_Interpreter::CommandBreakLoop(lcf::rpg::EventCommand const& /* com */) { // code 12220 auto& frame = GetFrame(); const auto& list = frame.commands; diff --git a/src/game_interpreter.h b/src/game_interpreter.h index 63aeec8ae8..192b543e3d 100644 --- a/src/game_interpreter.h +++ b/src/game_interpreter.h @@ -248,6 +248,7 @@ class Game_Interpreter bool CommandElseBranch(lcf::rpg::EventCommand const& com); bool CommandEndBranch(lcf::rpg::EventCommand const& com); bool CommandJumpToLabel(lcf::rpg::EventCommand const& com); + bool CommandLoop(lcf::rpg::EventCommand const& com); bool CommandBreakLoop(lcf::rpg::EventCommand const& com); bool CommandEndLoop(lcf::rpg::EventCommand const& com); bool CommandEraseEvent(lcf::rpg::EventCommand const& com);