Skip to content

Commit

Permalink
Merge pull request #2477 from ivan-mogilko/362--backport-routefinder-…
Browse files Browse the repository at this point in the history
…refact

Backport RouteFinder refactor to ags3 branch
  • Loading branch information
ivan-mogilko authored Jul 25, 2024
2 parents bd90cea + 65f471f commit 0467c1c
Show file tree
Hide file tree
Showing 27 changed files with 749 additions and 826 deletions.
2 changes: 1 addition & 1 deletion Common/gfx/allegrobitmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ bool Bitmap::ResizeSubBitmap(int width, int height)
return true;
}

bool Bitmap::CreateCopy(Bitmap *src, int color_depth)
bool Bitmap::CreateCopy(const Bitmap *src, int color_depth)
{
if (src == this || src->_alBitmap == _alBitmap)
return false; // cannot create a copy of yourself
Expand Down
7 changes: 6 additions & 1 deletion Common/gfx/allegrobitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Bitmap
bool ResizeSubBitmap(int width, int height);
// Creates a plain copy of the given bitmap, optionally converting to a different color depth;
// pass color depth 0 to keep the original one.
bool CreateCopy(Bitmap *src, int color_depth = 0);
bool CreateCopy(const Bitmap *src, int color_depth = 0);
// TODO: this is a temporary solution for plugin support
// Wraps a raw allegro BITMAP object, optionally owns it (will delete on disposal)
bool WrapAllegroBitmap(BITMAP *al_bmp, bool shared_data);
Expand All @@ -86,6 +86,11 @@ class Bitmap
return _alBitmap;
}

inline const BITMAP *GetAllegroBitmap() const
{
return _alBitmap;
}

// Is this a subbitmap, referencing a part of another, bigger one?
inline bool IsSubBitmap() const
{
Expand Down
2 changes: 1 addition & 1 deletion Common/gfx/bitmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Bitmap *CreateSubBitmap(Bitmap *src, const Rect &rc)
return bitmap;
}

Bitmap *CreateBitmapCopy(Bitmap *src, int color_depth)
Bitmap *CreateBitmapCopy(const Bitmap *src, int color_depth)
{
Bitmap *bitmap = new Bitmap();
if (!bitmap->CreateCopy(src, color_depth))
Expand Down
2 changes: 1 addition & 1 deletion Common/gfx/bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ namespace BitmapHelper
Bitmap *CreateSubBitmap(Bitmap *src, const Rect &rc);
// Creates a plain copy of the given bitmap, optionally converting to a different color depth;
// pass color depth 0 to keep the original one.
Bitmap *CreateBitmapCopy(Bitmap *src, int color_depth = 0);
Bitmap *CreateBitmapCopy(const Bitmap *src, int color_depth = 0);

// Creates Bitmap of wanted color depth from a raw pixel array of a (possibly different)
// specified color depth.
Expand Down
24 changes: 24 additions & 0 deletions Common/util/geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,30 @@ struct Point
return Point(X - p.X, Y - p.Y);
}

inline Point operator *(int mul) const
{
return Point(X * mul, Y * mul);
}

inline Point operator /(int div) const
{
return Point(X / div, Y / div);
}

inline Point &operator *=(int mul)
{
X *= mul;
Y *= mul;
return *this;
}

inline Point &operator /=(int div)
{
X /= div;
Y /= div;
return *this;
}

inline bool Equals(const int x, const int y) const
{
return X == x && Y == y;
Expand Down
84 changes: 40 additions & 44 deletions Engine/ac/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,10 @@ void Character_AddWaypoint(CharacterInfo *chaa, int x, int y) {
return;
}

MoveList *cmls = &mls[chaa->walking % TURNING_AROUND];
if (cmls->numstage >= MAXNEEDSTAGES)
{
debug_script_warn("Character::AddWaypoint: move is too complex, cannot add any further paths");
return;
}
MoveList &cmls = mls[chaa->walking % TURNING_AROUND];

// They're already walking there anyway
const Point &last_pos = cmls->GetLastPos();
const Point &last_pos = cmls.GetLastPos();
if (last_pos == Point(x, y))
return;

Expand All @@ -197,18 +192,16 @@ void Character_AddWaypoint(CharacterInfo *chaa, int x, int y) {
debug_script_warn("Character::AddWaypoint: called for '%s' with walk speed 0", chaa->scrname);
}

// There's an issue: the existing movelist is converted to room resolution,
// so we do this trick: convert last step to mask resolution, before calling
// There's an issue (for old games only): the existing movelist is converted to data resolution,
// so we do this trick: convert last step to game resolution, before calling
// a pathfinder api, and then we'll convert old and new last step back.
// TODO: figure out a better way of processing this!
const int last_stage = cmls->numstage - 1;
cmls->pos[last_stage] = { room_to_mask_coord(last_pos.X), room_to_mask_coord(last_pos.Y) };
const int dst_x = room_to_mask_coord(x);
const int dst_y = room_to_mask_coord(y);
if (add_waypoint_direct(cmls, dst_x, dst_y, move_speed_x, move_speed_y))
{
convert_move_path_to_room_resolution(cmls, last_stage, last_stage + 1);
}
const uint32_t last_stage = cmls.GetNumStages() - 1;
cmls.pos[last_stage] = { data_to_game_coord(last_pos.X), data_to_game_coord(last_pos.Y) };
const int dst_x = data_to_game_coord(x);
const int dst_y = data_to_game_coord(y);
Pathfinding::AddWaypointDirect(cmls, dst_x, dst_y, move_speed_x, move_speed_y);
convert_move_path_to_data_resolution(cmls, last_stage, last_stage + 1);
}

void Character_Animate(CharacterInfo *chaa, int loop, int delay, int repeat,
Expand Down Expand Up @@ -952,11 +945,10 @@ void Character_SetSpeed(CharacterInfo *chaa, int xspeed, int yspeed) {

if (chaa->walking > 0)
{
recalculate_move_speeds(&mls[chaa->walking % TURNING_AROUND], old_speedx, old_speedy, xspeed, yspeed);
Pathfinding::RecalculateMoveSpeeds(mls[chaa->walking % TURNING_AROUND], old_speedx, old_speedy, xspeed, yspeed);
}
}


void Character_StopMoving(CharacterInfo *charp) {

int chaa = charp->index_id;
Expand Down Expand Up @@ -1417,7 +1409,7 @@ int Character_GetMoving(CharacterInfo *chaa) {
int Character_GetDestinationX(CharacterInfo *chaa) {
if (chaa->walking) {
MoveList *cmls = &mls[chaa->walking % TURNING_AROUND];
return cmls->pos[cmls->numstage - 1].X;
return cmls->pos.back().X;
}
else
return chaa->x;
Expand All @@ -1426,7 +1418,7 @@ int Character_GetDestinationX(CharacterInfo *chaa) {
int Character_GetDestinationY(CharacterInfo *chaa) {
if (chaa->walking) {
MoveList *cmls = &mls[chaa->walking % TURNING_AROUND];
return cmls->pos[cmls->numstage - 1].Y;
return cmls->pos.back().Y;
}
else
return chaa->y;
Expand Down Expand Up @@ -1754,18 +1746,21 @@ void walk_character(int chac,int tox,int toy,int ignwal, bool autoWalkAnims) {
debug_script_warn("MoveCharacter: called for '%s' with walk speed 0", chin->scrname);
}

// Convert src and dest coords to the mask resolution, for pathfinder
const int src_x = room_to_mask_coord(chin->x);
const int src_y = room_to_mask_coord(chin->y);
const int dst_x = room_to_mask_coord(tox);
const int dst_y = room_to_mask_coord(toy);

int mslot = find_route(src_x, src_y, dst_x, dst_y, move_speed_x, move_speed_y,
prepare_walkable_areas(chac), chac+CHMLSOFFS, 1, ignwal);
if (mslot>0) {
// NOTE: for old games we assume the input coordinates are in the "data" coordinate system
const int src_x = data_to_game_coord(chin->x);
const int src_y = data_to_game_coord(chin->y);
const int dst_x = data_to_game_coord(tox);
const int dst_y = data_to_game_coord(toy);

const int mslot = chac + CHMLSOFFS;
MaskRouteFinder *pathfind = get_room_pathfinder();
pathfind->SetWalkableArea(prepare_walkable_areas(chac), thisroom.MaskResolution);
if (Pathfinding::FindRoute(mls[mslot], pathfind, src_x, src_y, dst_x, dst_y,
move_speed_x, move_speed_y, false, ignwal != 0))
{
chin->walking = mslot;
mls[mslot].direct = ignwal;
convert_move_path_to_room_resolution(&mls[mslot]);
convert_move_path_to_data_resolution(mls[mslot]);

if (wasStepFrac > 0.f)
{
Expand Down Expand Up @@ -1868,8 +1863,8 @@ void start_character_turning (CharacterInfo *chinf, int useloop, int no_diagonal
}

void fix_player_sprite(MoveList*cmls,CharacterInfo*chinf) {
const fixed xpmove = cmls->xpermove[cmls->onstage];
const fixed ypmove = cmls->ypermove[cmls->onstage];
const fixed xpmove = cmls->permove[cmls->onstage].X;
const fixed ypmove = cmls->permove[cmls->onstage].Y;

// if not moving, do nothing
if ((xpmove == 0) && (ypmove == 0))
Expand Down Expand Up @@ -2087,19 +2082,20 @@ void walk_or_move_character(CharacterInfo *chaa, int x, int y, int blocking, int

void walk_or_move_character_straight(CharacterInfo *chaa, int x, int y, int blocking, int direct, bool isWalk)
{
set_wallscreen(prepare_walkable_areas(chaa->index_id));

int from_mask_x = room_to_mask_coord(chaa->x);
int from_mask_y = room_to_mask_coord(chaa->y);
int to_mask_x = room_to_mask_coord(x);
int to_mask_y = room_to_mask_coord(y);
// NOTE: for old games we assume the input coordinates are in the "data" coordinate system
const int src_x = data_to_game_coord(chaa->x);
const int src_y = data_to_game_coord(chaa->y);
const int dst_x = data_to_game_coord(x);
const int dst_y = data_to_game_coord(y);

int movetox = x, movetoy = y;
if (!can_see_from(from_mask_x, from_mask_y, to_mask_x, to_mask_y)) {
int lastcx, lastcy;
get_lastcpos(lastcx, lastcy);
movetox = mask_to_room_coord(lastcx);
movetoy = mask_to_room_coord(lastcy);
int lastcx, lastcy;
MaskRouteFinder *pathfind = get_room_pathfinder();
pathfind->SetWalkableArea(prepare_walkable_areas(chaa->index_id), thisroom.MaskResolution);
if (!pathfind->CanSeeFrom(src_x, src_y, dst_x, dst_y, &lastcx, &lastcy))
{
movetox = game_to_data_coord(lastcx);
movetoy = game_to_data_coord(lastcy);
}

walk_or_move_character(chaa, movetox, movetoy, blocking, direct, isWalk);
Expand Down
2 changes: 1 addition & 1 deletion Engine/ac/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ int Character_GetSpeakingFrame(CharacterInfo *chaa);

//=============================================================================

struct MoveList;
class MoveList;
namespace AGS { namespace Common { class Bitmap; } }
using namespace AGS; // FIXME later

Expand Down
2 changes: 1 addition & 1 deletion Engine/ac/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2938,7 +2938,7 @@ void update_room_debug()
if (game.chars[debugMoveListChar].walking >= TURNING_AROUND)
mlsnum %= TURNING_AROUND;
const MoveList &cmls = mls[mlsnum];
for (int i = 0; i < cmls.numstage - 1; i++) {
for (uint32_t i = 0; i < cmls.GetNumStages() - 1; i++) {
short srcx = cmls.pos[i].X;
short srcy = cmls.pos[i].Y;
short targetx = cmls.pos[i + 1].X;
Expand Down
3 changes: 3 additions & 0 deletions Engine/ac/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "ac/overlay.h"
#include "ac/path_helper.h"
#include "ac/sys_events.h"
#include "ac/room.h"
#include "ac/roomstatus.h"
#include "ac/sprite.h"
#include "ac/spritecache.h"
Expand Down Expand Up @@ -497,6 +498,8 @@ void unload_game()

resetRoomStatuses();

dispose_room_pathfinder();

// Free game state and game struct
play = GamePlayState();
game = GameSetupStruct();
Expand Down
49 changes: 29 additions & 20 deletions Engine/ac/movelist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,23 @@ using namespace AGS::Engine;

float MoveList::GetStepLength() const
{
assert(numstage > 0);
float permove_x = fixtof(xpermove[onstage]);
float permove_y = fixtof(ypermove[onstage]);
assert(GetNumStages() > 0);
float permove_x = fixtof(permove[onstage].X);
float permove_y = fixtof(permove[onstage].Y);
return std::sqrt(permove_x * permove_x + permove_y * permove_y);
}

float MoveList::GetPixelUnitFraction() const
{
assert(numstage > 0);
float distance = GetStepLength() * onpart;
assert(GetNumStages() > 0);
const float distance = GetStepLength() * onpart;
return distance - std::floor(distance);
}

void MoveList::SetPixelUnitFraction(float frac)
{
assert(numstage > 0);
float permove_dist = GetStepLength();
assert(GetNumStages() > 0);
const float permove_dist = GetStepLength();
onpart = permove_dist > 0.f ? (1.f / permove_dist) * frac : 0.f;
}

Expand All @@ -51,17 +51,13 @@ HSaveError MoveList::ReadFromSavegame(Stream *in, int32_t cmp_ver)
}

*this = MoveList(); // reset struct
numstage = in->ReadInt32();
uint32_t numstage = in->ReadInt32();
pos.resize(numstage);
permove.resize(numstage);
if ((numstage == 0) && cmp_ver >= kMoveSvgVersion_36109)
{
return HSaveError::None();
}
// TODO: reimplement MoveList stages as vector to avoid these limits
if (numstage > MAXNEEDSTAGES)
{
return new SavegameError(kSvgErr_IncompatibleEngine,
String::FromFormat("Incompatible number of movelist steps (count: %d, max : %d).", numstage, MAXNEEDSTAGES));
}

from.X = in->ReadInt32();
from.Y = in->ReadInt32();
Expand All @@ -72,13 +68,19 @@ HSaveError MoveList::ReadFromSavegame(Stream *in, int32_t cmp_ver)
doneflag = in->ReadInt8();
direct = in->ReadInt8();

for (int i = 0; i < numstage; ++i)
for (uint32_t i = 0; i < numstage; ++i)
{ // X & Y was packed as high/low shorts, and hence reversed in lo-end
pos[i].Y = in->ReadInt16();
pos[i].X = in->ReadInt16();
}
in->ReadArrayOfInt32(xpermove, numstage);
in->ReadArrayOfInt32(ypermove, numstage);
for (uint32_t i = 0; i < numstage; ++i)
{
permove[i].X = in->ReadInt32();
}
for (uint32_t i = 0; i < numstage; ++i)
{
permove[i].Y = in->ReadInt32();
}

// Some variables require conversion depending on a save version
if (cmp_ver < kMoveSvgVersion_36109)
Expand All @@ -91,6 +93,7 @@ HSaveError MoveList::ReadFromSavegame(Stream *in, int32_t cmp_ver)

void MoveList::WriteToSavegame(Stream *out) const
{
const uint32_t numstage = GetNumStages();
out->WriteInt32(numstage);
if (numstage == 0)
return;
Expand All @@ -104,11 +107,17 @@ void MoveList::WriteToSavegame(Stream *out) const
out->WriteInt8(doneflag);
out->WriteInt8(direct);

for (int i = 0; i < numstage; ++i)
for (uint32_t i = 0; i < numstage; ++i)
{ // X & Y was packed as high/low shorts, and hence reversed in lo-end
out->WriteInt16(pos[i].Y);
out->WriteInt16(pos[i].X);
}
out->WriteArrayOfInt32(xpermove, numstage);
out->WriteArrayOfInt32(ypermove, numstage);
for (uint32_t i = 0; i < numstage; ++i)
{
out->WriteInt32(permove[i].X);
}
for (uint32_t i = 0; i < numstage; ++i)
{
out->WriteInt32(permove[i].Y);
}
}
Loading

0 comments on commit 0467c1c

Please sign in to comment.