tibia-rme/source/map_drawer.h
Victor 21b234e2ab
feat: deferred rendering pipeline, memory optimization, and async map cleanup (#173)
New Features:
- Scene caching with render-to-texture and blitting for faster map redraws.
- Explicit blend-mode controls and FBO-backed render-to-texture workflow.

Bug Fixes:
- More robust sprite-sheet reload and texture release behavior.
- Safer editor/tab shutdown with ensured live-server closure and deferred deletion.

Performance:
- Reworked GPU batching/streaming and command-based flushing for fewer draw calls and efficient uploads.
- Smarter scene invalidation to avoid unnecessary re-renders.

UX:
- Undo/redo now refreshes editor views more reliably.
2026-04-25 10:35:24 -03:00

269 lines
8.1 KiB
C++

//////////////////////////////////////////////////////////////////////
// This file is part of Remere's Map Editor
//////////////////////////////////////////////////////////////////////
// Remere's Map Editor 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.
//
// Remere's Map Editor 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/>.
//////////////////////////////////////////////////////////////////////
#ifndef RME_MAP_DRAWER_H_
#define RME_MAP_DRAWER_H_
#include <cstdint>
#include <unordered_map>
#include <utility>
#include "light_drawer.h"
#include "gl_renderer.h"
class GameSprite;
struct TooltipEntry {
std::string label; // "id: ", "aid: ", "text: ", "wp: "
std::string value; // "2597", "80", "Guild Wars"
};
struct MapTooltip {
enum class Limits {
MAX_VALUE_DISPLAY = 1024,
MAX_WIDTH = 1024,
};
MapTooltip(int map_x, int map_y, int map_z, uint8_t r, uint8_t g, uint8_t b) :
map_x(map_x), map_y(map_y), map_z(map_z), r(r), g(g), b(b) { }
void addEntry(const std::string &label, const std::string &value) {
std::string val = value;
if (val.size() > static_cast<size_t>(std::to_underlying(Limits::MAX_VALUE_DISPLAY))) {
val = val.substr(0, static_cast<size_t>(std::to_underlying(Limits::MAX_VALUE_DISPLAY))) + "...";
}
entries.emplace_back(label, val);
}
int map_x;
int map_y;
int map_z;
uint8_t r, g, b;
std::vector<TooltipEntry> entries;
};
// Storage during drawing, for option caching
struct DrawingOptions {
public:
DrawingOptions();
void SetIngame();
void SetDefault();
bool isOnlyColors() const noexcept;
bool isTileIndicators() const noexcept;
bool isTooltips() const noexcept;
bool transparent_floors;
bool transparent_items;
bool show_ingame_box;
bool show_light_strength;
bool show_lights;
bool ingame;
bool dragging;
int show_grid;
bool show_all_floors;
bool show_monsters;
bool show_spawns_monster;
bool show_npcs;
bool show_spawns_npc;
bool show_houses;
bool show_shade;
bool show_special_tiles;
bool show_items;
bool highlight_items;
bool show_blocking;
bool show_tooltips;
bool show_performance_stats;
bool show_as_minimap;
bool show_only_colors;
bool show_only_modified;
bool show_preview;
bool show_hooks;
bool show_pickupables;
bool show_moveables;
bool show_avoidables;
bool hide_items_when_zoomed;
};
class MapCanvas;
struct BlitOptions {
bool adjustZoom = false;
bool isEditorSprite = false;
Outfit outfit = {};
int spriteId = 0;
SpriteUV uv = { 0.f, 0.f, 1.f, 1.f };
};
class MapDrawer {
MapCanvas* canvas;
Editor &editor;
DrawingOptions options;
std::shared_ptr<LightDrawer> light_drawer = std::make_shared<LightDrawer>();
std::unique_ptr<GLRenderer> renderer = std::make_unique<GLRenderer>();
bool isSceneDirty() const;
// Scene cache tracking
int prevScrollX = -1;
int prevScrollY = -1;
float prevZoom = -1.f;
int prevFloor = -1;
int prevStartZ = -1;
int prevScreenW = -1;
int prevScreenH = -1;
bool fboDirty = true;
float zoom;
float globalTooltipFade = 0.0f;
uint32_t current_house_id;
int mouse_map_x, mouse_map_y;
int start_x, start_y, start_z;
int end_x, end_y, end_z, superend_z;
int view_scroll_x, view_scroll_y;
int screensize_x, screensize_y;
int tile_size;
int floor;
protected:
std::vector<MapTooltip> tooltips;
std::unordered_map<uint64_t, float> tooltipFadeAlpha;
wxStopWatch pos_indicator_timer;
Position pos_indicator;
// Performance monitoring
wxStopWatch fps_timer;
int frame_count = 0;
double current_fps = 0.0;
wxStopWatch perf_update_timer;
double current_cpu = 0.0;
size_t current_ram = 0;
#ifdef __WINDOWS__
ULARGE_INTEGER last_cpu_time;
ULARGE_INTEGER last_sys_time;
ULARGE_INTEGER last_now_time;
#else
uint64_t last_total_time = 0;
uint64_t last_process_time = 0;
#endif
public:
MapDrawer(MapCanvas* canvas);
~MapDrawer();
void markDirty() {
fboDirty = true;
}
bool dragging;
bool dragging_draw;
void SetupVars();
void SetupGL();
void Release();
void Draw();
void DrawBackground();
void DrawShade(int mapz);
void DrawMap();
void DrawSecondaryMap(int mapz);
void DrawDraggingShadow();
void DrawHigherFloors();
void DrawSelectionBox();
void DrawLiveCursors();
void DrawBrush();
void DrawIngameBox();
void DrawGrid();
void DrawTooltips();
std::pair<float, float> MeasureTooltipText(const MapTooltip &tp);
void RenderTooltipText(const MapTooltip &tp, float startx, float starty, float fade = 1.0f);
void DrawPerformanceStats();
void TakeScreenshot(uint8_t* screenshot_buffer);
void ShowPositionIndicator(const Position &position);
long GetPositionIndicatorTime() const {
const long time = pos_indicator_timer.Time();
if (time < rme::PositionIndicatorDuration) {
return time;
}
return 0;
}
DrawingOptions &getOptions() noexcept {
return options;
}
protected:
void BlitItem(int &screenx, int &screeny, const Tile* tile, const Item* item, bool ephemeral = false, int red = 255, int green = 255, int blue = 255, int alpha = 255);
void BlitItem(int &screenx, int &screeny, const Position &pos, const Item* item, bool ephemeral = false, int red = 255, int green = 255, int blue = 255, int alpha = 255);
void BlitSpriteType(int screenx, int screeny, uint32_t spriteid, int red = 255, int green = 255, int blue = 255, int alpha = 255);
void BlitSpriteType(int screenx, int screeny, GameSprite* spr, int red = 255, int green = 255, int blue = 255, int alpha = 255);
// Performance monitoring helpers
void UpdateRAMUsage();
void UpdateCPUUsage();
std::string FormatPerformanceStats() const;
void BlitCreature(int screenx, int screeny, const Monster* npc, int red = 255, int green = 255, int blue = 255, int alpha = 255);
void BlitCreature(int screenx, int screeny, const Npc* c, int red = 255, int green = 255, int blue = 255, int alpha = 255);
void BlitCreature(int screenx, int screeny, const Outfit &outfit, const Direction &dir, int red = 255, int green = 255, int blue = 255, int alpha = 255);
void DrawTile(TileLocation* tile);
void DrawBrushIndicator(int x, int y, [[maybe_unused]] Brush* brush, uint8_t r, uint8_t g, uint8_t b);
void DrawHookIndicator(int x, int y, const ItemType &type);
void DrawLightStrength(int x, int y, const Item*&item);
void DrawTileIndicators(TileLocation* location);
void DrawIndicator(int x, int y, int indicator, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255, uint8_t a = 255);
void DrawPositionIndicator(int z);
void DrawLight() const;
void WriteTooltip(const Item* item, MapTooltip &tooltip);
void WriteTooltip(const Waypoint* waypoint, MapTooltip &tooltip);
MapTooltip &MakeTooltip(int map_x, int map_y, int map_z, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255);
void AddLight(TileLocation* location);
enum BrushColor {
COLOR_BRUSH,
COLOR_HOUSE_BRUSH,
COLOR_FLAG_BRUSH,
COLOR_SPAWN_BRUSH,
COLOR_SPAWN_NPC_BRUSH,
COLOR_ERASER,
COLOR_VALID,
COLOR_INVALID,
COLOR_BLANK,
};
void getColor(Brush* brush, const Position &position, uint8_t &r, uint8_t &g, uint8_t &b);
void glBlitTexture(int x, int y, int textureId, const GLColor &color, const BlitOptions &opts = BlitOptions {});
void glBlitSquare(int x, int y, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha, int size = rme::TileSize) const;
void glBlitSquare(int x, int y, const wxColor &color, int size = rme::TileSize) const;
void getBrushColor(BrushColor color, uint8_t &r, uint8_t &g, uint8_t &b, uint8_t &a);
void getCheckColor(Brush* brush, const Position &pos, uint8_t &r, uint8_t &g, uint8_t &b, uint8_t &a);
void drawRect(int x, int y, int w, int h, const wxColor &color, float width = 1.0f);
void drawFilledRect(int x, int y, int w, int h, const wxColor &color);
private:
void getDrawPosition(const Position &position, int &x, int &y);
};
#endif