From e21f0f2b69ac945e1ffbffa829c4b32f7b53d2ea Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Fri, 11 Aug 2023 09:14:05 +0300 Subject: [PATCH 01/21] dynamic texture loading --- library/include/modules/Textures.h | 21 ++- library/modules/Textures.cpp | 236 ++++++++++++++++++++++++----- 2 files changed, 217 insertions(+), 40 deletions(-) diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 3b9d32541..7b2ac78d3 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -1,8 +1,14 @@ #pragma once +#include + #include "Export.h" #include "ColorText.h" +#include + +using TexposHandle = uintptr_t; + namespace DFHack { /** @@ -12,6 +18,19 @@ namespace DFHack { */ namespace Textures { +/** + * Load texture and get handle. + * Keep it to obtain valid texpos. + */ +DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); + +/** + * Get texpos by handle. + * Always use this function, if you need to get valid texpos for your texure. + * Texpos can change on game textures reset, but handle will be the same. + */ +DFHACK_EXPORT std::optional getTexposByHandle(TexposHandle handle); + /** * Call this on DFHack init and on every viewscreen change so we can reload * and reindex textures as needed. @@ -71,4 +90,4 @@ DFHACK_EXPORT long getPanelBordersTexposStart(); DFHACK_EXPORT long getWindowBordersTexposStart(); } -} +} \ No newline at end of file diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 9976a3c4f..c3ec15f89 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -1,3 +1,6 @@ +#include +#include + #include "Internal.h" #include "modules/DFSDL.h" @@ -5,10 +8,13 @@ #include "Debug.h" #include "PluginManager.h" +#include "VTableInterpose.h" #include "df/enabler.h" - -#include +#include "df/viewscreen_adopt_regionst.h" +#include "df/viewscreen_loadgamest.h" +#include "df/viewscreen_new_regionst.h" +#include "df/viewscreen_new_arenast.h" using df::global::enabler; using namespace DFHack; @@ -19,6 +25,7 @@ namespace DFHack { } static bool g_loaded = false; +static bool g_dynamic_loaded = false; static long g_num_dfhack_textures = 0; static long g_dfhack_logo_texpos_start = -1; static long g_green_pin_texpos_start = -1; @@ -34,6 +41,10 @@ static long g_bold_borders_texpos_start = -1; static long g_panel_borders_texpos_start = -1; static long g_window_borders_texpos_start = -1; +static std::unordered_map g_handle_to_texpos; +static std::unordered_map g_handle_to_surface; +static std::mutex g_adding_mutex; + // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -41,7 +52,7 @@ static long g_window_borders_texpos_start = -1; // // It uses the same pixel format (RGBA, R at lowest address) regardless of // hardware. -SDL_Surface * canonicalize_format(SDL_Surface *src) { +SDL_Surface* canonicalize_format(SDL_Surface *src) { SDL_PixelFormat fmt; fmt.palette = NULL; fmt.BitsPerPixel = 32; @@ -57,7 +68,7 @@ SDL_Surface * canonicalize_format(SDL_Surface *src) { fmt.Bmask = 255 << fmt.Bshift; fmt.Amask = 255 << fmt.Ashift; - SDL_Surface *tgt = DFSDL_ConvertSurface(src, &fmt, SDL_SWSURFACE); + SDL_Surface* tgt = DFSDL_ConvertSurface(src, &fmt, SDL_SWSURFACE); DFSDL_FreeSurface(src); for (int x = 0; x < tgt->w; ++x) { for (int y = 0; y < tgt->h; ++y) { @@ -72,13 +83,148 @@ SDL_Surface * canonicalize_format(SDL_Surface *src) { return tgt; } +// register surface in texture raws, get a texpos +static long add_texture(SDL_Surface* surface) { + std::lock_guard lg_add_texture(g_adding_mutex); + auto texpos = enabler->textures.raws.size(); + enabler->textures.raws.push_back(surface); + return texpos; +} + +TexposHandle Textures::loadTexture(SDL_Surface* surface) { + if (!surface) + return 0; // should be some error, i guess + + auto handle = reinterpret_cast(surface); // not the best way? + g_handle_to_surface.emplace(handle, surface); + surface->refcount++; // prevent destruct on next FreeSurface by game + auto texpos = add_texture(surface); + g_handle_to_texpos.emplace(handle, texpos); + return handle; +} + +std::optional Textures::getTexposByHandle(TexposHandle handle) { + if (!handle) + return std::nullopt; + + if (auto it = g_handle_to_texpos.find(handle); it != g_handle_to_texpos.end()) + return it->second; + + if (auto it = g_handle_to_surface.find(handle); it != g_handle_to_surface.end()) { + it->second->refcount++; // prevent destruct on next FreeSurface by game + auto texpos = add_texture(it->second); + g_handle_to_texpos.emplace(handle, texpos); + return texpos; + } + + return std::nullopt; +} + +static void reset_texpos() { + g_handle_to_texpos.clear(); +} + +static void reset_surface() { + for (auto& entry : g_handle_to_surface) { + DFSDL_FreeSurface(entry.second); + } + g_handle_to_surface.clear(); +} + +// reset point on New Game +struct tracking_stage_new_region : df::viewscreen_new_regionst { + typedef df::viewscreen_new_regionst interpose_base; + + DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { + if (this->m_raw_load_stage != this->raw_load_stage) { + this->m_raw_load_stage = this->raw_load_stage; + if (this->m_raw_load_stage == 1) + reset_texpos(); + } + INTERPOSE_NEXT(logic)(); + } + + private: + inline static int m_raw_load_stage = -2; // not valid state at the start +}; +IMPLEMENT_VMETHOD_INTERPOSE(tracking_stage_new_region, logic); + +// reset point on New Game in Existing World +struct tracking_stage_adopt_region : df::viewscreen_adopt_regionst { + typedef df::viewscreen_adopt_regionst interpose_base; + + DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { + if (this->m_cur_step != this->cur_step) { + this->m_cur_step = this->cur_step; + if (this->m_cur_step == df::viewscreen_adopt_regionst::T_cur_step::ProcessingRawData) + reset_texpos(); + } + INTERPOSE_NEXT(logic)(); + } + + private: + inline static int m_cur_step = -2; // not valid state at the start +}; +IMPLEMENT_VMETHOD_INTERPOSE(tracking_stage_adopt_region, logic); + +// reset point on Load Game +struct tracking_stage_load_region : df::viewscreen_loadgamest { + typedef df::viewscreen_loadgamest interpose_base; + + DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { + if (this->m_cur_step != this->cur_step) { + this->m_cur_step = this->cur_step; + if (this->m_cur_step == df::viewscreen_loadgamest::T_cur_step::ProcessingRawData) + reset_texpos(); + } + INTERPOSE_NEXT(logic)(); + } + + private: + inline static int m_cur_step = -2; // not valid state at the start +}; +IMPLEMENT_VMETHOD_INTERPOSE(tracking_stage_load_region, logic); + +// reset point on New Arena +struct tracking_stage_new_arena : df::viewscreen_new_arenast { + typedef df::viewscreen_new_arenast interpose_base; + + DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { + if (this->m_cur_step != this->cur_step) { + this->m_cur_step = this->cur_step; + if (this->m_cur_step == 0) + reset_texpos(); + } + INTERPOSE_NEXT(logic)(); + } + + private: + inline static int m_cur_step = -2; // not valid state at the start +}; +IMPLEMENT_VMETHOD_INTERPOSE(tracking_stage_new_arena, logic); + +static void + install_reset_point() { + INTERPOSE_HOOK(tracking_stage_new_region, logic).apply(); + INTERPOSE_HOOK(tracking_stage_adopt_region, logic).apply(); + INTERPOSE_HOOK(tracking_stage_load_region, logic).apply(); + INTERPOSE_HOOK(tracking_stage_new_arena, logic).apply(); +} + +static void uninstall_reset_point() { + INTERPOSE_HOOK(tracking_stage_new_region, logic).remove(); + INTERPOSE_HOOK(tracking_stage_adopt_region, logic).remove(); + INTERPOSE_HOOK(tracking_stage_load_region, logic).remove(); + INTERPOSE_HOOK(tracking_stage_new_arena, logic).remove(); +} + const uint32_t TILE_WIDTH_PX = 8; const uint32_t TILE_HEIGHT_PX = 12; -static size_t load_textures(color_ostream & out, const char * fname, - long *texpos_start, - int tile_w = TILE_WIDTH_PX, - int tile_h = TILE_HEIGHT_PX) { +static size_t load_tiles_from_image(color_ostream& out, const char* fname, + long* texpos_start, + int tile_w = TILE_WIDTH_PX, + int tile_h = TILE_HEIGHT_PX) { SDL_Surface *s = DFIMG_Load(fname); if (!s) { out.printerr("unable to load textures from '%s'\n", fname); @@ -91,7 +237,7 @@ static size_t load_textures(color_ostream & out, const char * fname, long count = 0; for (int y = 0; y < dimy; y++) { for (int x = 0; x < dimx; x++) { - SDL_Surface *tile = DFSDL_CreateRGBSurface(0, // SDL_SWSURFACE + SDL_Surface* tile = DFSDL_CreateRGBSurface(0, // SDL_SWSURFACE tile_w, tile_h, 32, s->format->Rmask, s->format->Gmask, s->format->Bmask, s->format->Amask); @@ -120,7 +266,12 @@ static size_t load_textures(color_ostream & out, const char * fname, // texture count so our textures will no longer be freed when worlds are // unloaded. // -void Textures::init(color_ostream &out) { +void Textures::init(color_ostream& out) { + if (!g_dynamic_loaded) { + g_dynamic_loaded = true; + install_reset_point(); + } + if (!enabler) return; @@ -134,32 +285,32 @@ void Textures::init(color_ostream &out) { bool is_pre_world = num_textures == textures.init_texture_size; - g_num_dfhack_textures = load_textures(out, "hack/data/art/dfhack.png", - &g_dfhack_logo_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/green-pin.png", - &g_green_pin_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/red-pin.png", - &g_red_pin_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/icons.png", - &g_icons_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/on-off.png", - &g_on_off_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/pathable.png", - &g_pathable_texpos_start, 32, 32); - g_num_dfhack_textures += load_textures(out, "hack/data/art/unsuspend.png", - &g_unsuspend_texpos_start, 32, 32); - g_num_dfhack_textures += load_textures(out, "hack/data/art/control-panel.png", - &g_control_panel_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/border-thin.png", - &g_thin_borders_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/border-medium.png", - &g_medium_borders_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/border-bold.png", - &g_bold_borders_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/border-panel.png", - &g_panel_borders_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/border-window.png", - &g_window_borders_texpos_start); + g_num_dfhack_textures = load_tiles_from_image(out, "hack/data/art/dfhack.png", + &g_dfhack_logo_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/green-pin.png", + &g_green_pin_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/red-pin.png", + &g_red_pin_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/icons.png", + &g_icons_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/on-off.png", + &g_on_off_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/pathable.png", + &g_pathable_texpos_start, 32, 32); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/unsuspend.png", + &g_unsuspend_texpos_start, 32, 32); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/control-panel.png", + &g_control_panel_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-thin.png", + &g_thin_borders_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-medium.png", + &g_medium_borders_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-bold.png", + &g_bold_borders_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-panel.png", + &g_panel_borders_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-window.png", + &g_window_borders_texpos_start); DEBUG(textures,out).print("loaded %ld textures\n", g_num_dfhack_textures); @@ -176,8 +327,8 @@ void Textures::cleanup() { if (!g_loaded) return; - auto & textures = enabler->textures; - auto &raws = textures.raws; + auto& textures = enabler->textures; + auto& raws = textures.raws; size_t texpos_end = g_dfhack_logo_texpos_start + g_num_dfhack_textures - 1; for (size_t idx = g_dfhack_logo_texpos_start; idx <= texpos_end; ++idx) { DFSDL_FreeSurface((SDL_Surface *)raws[idx]); @@ -190,6 +341,13 @@ void Textures::cleanup() { g_loaded = false; g_num_dfhack_textures = 0; g_dfhack_logo_texpos_start = -1; + + if (g_dynamic_loaded) { + g_dynamic_loaded = false; + reset_texpos(); + reset_surface(); + uninstall_reset_point(); + } } long Textures::getDfhackLogoTexposStart() { @@ -242,4 +400,4 @@ long Textures::getPanelBordersTexposStart() { long Textures::getWindowBordersTexposStart() { return g_window_borders_texpos_start; -} +} \ No newline at end of file From 4bbcc7b05de2af3898b03848970c85043b97b62c Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Fri, 11 Aug 2023 09:48:03 +0300 Subject: [PATCH 02/21] eof fix --- library/modules/Textures.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index c3ec15f89..a05056a2d 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -400,4 +400,4 @@ long Textures::getPanelBordersTexposStart() { long Textures::getWindowBordersTexposStart() { return g_window_borders_texpos_start; -} \ No newline at end of file +} From 3e18e2f6fe8ee67addc58e7b94881fd3327a5b5a Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Fri, 11 Aug 2023 09:50:51 +0300 Subject: [PATCH 03/21] eof fix one more time --- library/include/modules/Textures.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 7b2ac78d3..17e28c099 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -90,4 +90,4 @@ DFHACK_EXPORT long getPanelBordersTexposStart(); DFHACK_EXPORT long getWindowBordersTexposStart(); } -} \ No newline at end of file +} From e81a90821a3e27338e352cda713a08ef19fdf1c8 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Fri, 11 Aug 2023 21:40:41 +0300 Subject: [PATCH 04/21] review --- library/Core.cpp | 1 + library/include/modules/Textures.h | 20 +++++-- library/modules/Textures.cpp | 91 +++++++++++++++++++----------- 3 files changed, 76 insertions(+), 36 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 9df45a869..d2ef1174b 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1692,6 +1692,7 @@ bool Core::InitSimulationThread() } std::cerr << "Initializing textures.\n"; Textures::init(con); + Textures::initDynamic(con); // create mutex for syncing with interactive tasks std::cerr << "Initializing plugins.\n"; // create plugin manager diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 17e28c099..ff1007dad 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -1,13 +1,14 @@ #pragma once -#include +#include +#include #include "Export.h" #include "ColorText.h" #include -using TexposHandle = uintptr_t; +typedef typename void* TexposHandle; namespace DFHack { @@ -24,18 +25,29 @@ namespace Textures { */ DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); +/** + * Load tileset from image file. + * Return vector of handles to obtain valid texposes. + */ +DFHACK_EXPORT std::vector loadTileset(const std::string& file, int tile_px_w, int tile_px_h); + /** * Get texpos by handle. * Always use this function, if you need to get valid texpos for your texure. * Texpos can change on game textures reset, but handle will be the same. */ -DFHACK_EXPORT std::optional getTexposByHandle(TexposHandle handle); +DFHACK_EXPORT long getTexposByHandle(TexposHandle handle); /** * Call this on DFHack init and on every viewscreen change so we can reload * and reindex textures as needed. */ -void init(DFHack::color_ostream &out); +void init(DFHack::color_ostream& out); + +/** + * Call this on DFHack init just once to setup interposed handlers. + */ +void initDynamic(DFHack::color_ostream& out); /** * Call this when DFHack is being unloaded. diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index a05056a2d..ec9fa41f1 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -25,7 +25,6 @@ namespace DFHack { } static bool g_loaded = false; -static bool g_dynamic_loaded = false; static long g_num_dfhack_textures = 0; static long g_dfhack_logo_texpos_start = -1; static long g_green_pin_texpos_start = -1; @@ -45,6 +44,9 @@ static std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_surface; static std::mutex g_adding_mutex; +const uint32_t TILE_WIDTH_PX = 8; +const uint32_t TILE_HEIGHT_PX = 12; + // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -52,7 +54,7 @@ static std::mutex g_adding_mutex; // // It uses the same pixel format (RGBA, R at lowest address) regardless of // hardware. -SDL_Surface* canonicalize_format(SDL_Surface *src) { +SDL_Surface* canonicalize_format(SDL_Surface* src) { SDL_PixelFormat fmt; fmt.palette = NULL; fmt.BitsPerPixel = 32; @@ -95,7 +97,7 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { if (!surface) return 0; // should be some error, i guess - auto handle = reinterpret_cast(surface); // not the best way? + auto handle = reinterpret_cast(surface); g_handle_to_surface.emplace(handle, surface); surface->refcount++; // prevent destruct on next FreeSurface by game auto texpos = add_texture(surface); @@ -103,21 +105,53 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { return handle; } -std::optional Textures::getTexposByHandle(TexposHandle handle) { +std::vector Textures::loadTileset(const std::string& file, + int tile_px_w = TILE_WIDTH_PX, + int tile_px_h = TILE_HEIGHT_PX) { + std::vector handles{}; + + SDL_Surface* surface = DFIMG_Load(file.c_str()); + if (!surface) { + ERR(textures).printerr("unable to load textures from '%s'\n", file.c_str()); + return handles; + } + + surface = canonicalize_format(surface); + int dimx = surface->w / tile_px_w; + int dimy = surface->h / tile_px_h; + for (int y = 0; y < dimy; y++) { + for (int x = 0; x < dimx; x++) { + SDL_Surface* tile = DFSDL_CreateRGBSurface(0, tile_px_w, tile_px_h, 32, + surface->format->Rmask, surface->format->Gmask, + surface->format->Bmask, surface->format->Amask); + SDL_Rect vp{ tile_px_w * x, tile_px_h * y, tile_px_w, tile_px_h }; + DFSDL_UpperBlit(surface, &vp, tile, NULL); + auto handle = Textures::loadTexture(tile); + handles.push_back(handle); + } + } + + DFSDL_FreeSurface(surface); + DEBUG(textures).print("loaded %ld textures from '%s'\n", handles.size(), file.c_str()); + + return handles; +} + +long Textures::getTexposByHandle(TexposHandle handle) { if (!handle) - return std::nullopt; + return -1; - if (auto it = g_handle_to_texpos.find(handle); it != g_handle_to_texpos.end()) - return it->second; + if (g_handle_to_texpos.contains(handle)) + return g_handle_to_texpos[handle]; - if (auto it = g_handle_to_surface.find(handle); it != g_handle_to_surface.end()) { - it->second->refcount++; // prevent destruct on next FreeSurface by game - auto texpos = add_texture(it->second); - g_handle_to_texpos.emplace(handle, texpos); - return texpos; + if (g_handle_to_surface.contains(handle)) { + g_handle_to_surface[handle]->refcount++; // prevent destruct on next FreeSurface by game + auto texpos = add_texture(g_handle_to_surface[handle]); + g_handle_to_texpos.emplace(handle, texpos); + return texpos; } - return std::nullopt; + return -1; } static void reset_texpos() { @@ -203,8 +237,7 @@ struct tracking_stage_new_arena : df::viewscreen_new_arenast { }; IMPLEMENT_VMETHOD_INTERPOSE(tracking_stage_new_arena, logic); -static void - install_reset_point() { +static void install_reset_point() { INTERPOSE_HOOK(tracking_stage_new_region, logic).apply(); INTERPOSE_HOOK(tracking_stage_adopt_region, logic).apply(); INTERPOSE_HOOK(tracking_stage_load_region, logic).apply(); @@ -218,14 +251,11 @@ static void uninstall_reset_point() { INTERPOSE_HOOK(tracking_stage_new_arena, logic).remove(); } -const uint32_t TILE_WIDTH_PX = 8; -const uint32_t TILE_HEIGHT_PX = 12; - static size_t load_tiles_from_image(color_ostream& out, const char* fname, long* texpos_start, int tile_w = TILE_WIDTH_PX, int tile_h = TILE_HEIGHT_PX) { - SDL_Surface *s = DFIMG_Load(fname); + SDL_Surface* s = DFIMG_Load(fname); if (!s) { out.printerr("unable to load textures from '%s'\n", fname); return 0; @@ -258,6 +288,11 @@ static size_t load_tiles_from_image(color_ostream& out, const char* fname, return count; } +void Textures::initDynamic(color_ostream& out) { + install_reset_point(); + DEBUG(textures, out).print("dynamic texture reset points installed"); +} + // DFHack could conceivably be loaded at any time, so we need to be able to // handle loading textures before or after a world is loaded. // If a world is already loaded, then append our textures to the raws. they'll @@ -267,15 +302,10 @@ static size_t load_tiles_from_image(color_ostream& out, const char* fname, // unloaded. // void Textures::init(color_ostream& out) { - if (!g_dynamic_loaded) { - g_dynamic_loaded = true; - install_reset_point(); - } - if (!enabler) return; - auto & textures = enabler->textures; + auto& textures = enabler->textures; long num_textures = textures.raws.size(); if (num_textures <= g_dfhack_logo_texpos_start) g_loaded = false; @@ -324,6 +354,10 @@ void Textures::init(color_ostream& out) { // It's ok to leave NULLs in the raws list (according to usage in g_src) void Textures::cleanup() { + reset_texpos(); + reset_surface(); + uninstall_reset_point(); + if (!g_loaded) return; @@ -341,13 +375,6 @@ void Textures::cleanup() { g_loaded = false; g_num_dfhack_textures = 0; g_dfhack_logo_texpos_start = -1; - - if (g_dynamic_loaded) { - g_dynamic_loaded = false; - reset_texpos(); - reset_surface(); - uninstall_reset_point(); - } } long Textures::getDfhackLogoTexposStart() { From fe8bd4fa786369f7a95ae7925fc992095cc1fb2d Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sat, 12 Aug 2023 16:11:42 +0300 Subject: [PATCH 05/21] assets use dynamic texture loading --- library/Core.cpp | 2 - library/LuaApi.cpp | 13 +- library/include/modules/Textures.h | 67 ++----- library/lua/gui.lua | 38 +++- library/modules/Textures.cpp | 279 +++++++---------------------- plugins/lua/buildingplan/pens.lua | 31 ++-- plugins/lua/hotkeys.lua | 40 +++-- plugins/pathable.cpp | 6 +- 8 files changed, 150 insertions(+), 326 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index d2ef1174b..4950e848d 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1692,7 +1692,6 @@ bool Core::InitSimulationThread() } std::cerr << "Initializing textures.\n"; Textures::init(con); - Textures::initDynamic(con); // create mutex for syncing with interactive tasks std::cerr << "Initializing plugins.\n"; // create plugin manager @@ -2219,7 +2218,6 @@ void Core::onStateChange(color_ostream &out, state_change_event event) } break; case SC_VIEWSCREEN_CHANGED: - Textures::init(out); break; default: break; diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 578bb4746..61a7eb83d 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1710,18 +1710,7 @@ static const luaL_Reg dfhack_job_funcs[] = { /***** Textures module *****/ static const LuaWrapper::FunctionReg dfhack_textures_module[] = { - WRAPM(Textures, getDfhackLogoTexposStart), - WRAPM(Textures, getGreenPinTexposStart), - WRAPM(Textures, getRedPinTexposStart), - WRAPM(Textures, getIconsTexposStart), - WRAPM(Textures, getOnOffTexposStart), - WRAPM(Textures, getMapUnsuspendTexposStart), - WRAPM(Textures, getControlPanelTexposStart), - WRAPM(Textures, getThinBordersTexposStart), - WRAPM(Textures, getMediumBordersTexposStart), - WRAPM(Textures, getBoldBordersTexposStart), - WRAPM(Textures, getPanelBordersTexposStart), - WRAPM(Textures, getWindowBordersTexposStart), + WRAPM(Textures, getAsset), { NULL, NULL } }; diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index ff1007dad..9569a257a 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -1,10 +1,10 @@ #pragma once -#include #include +#include -#include "Export.h" #include "ColorText.h" +#include "Export.h" #include @@ -29,7 +29,8 @@ DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); * Load tileset from image file. * Return vector of handles to obtain valid texposes. */ -DFHACK_EXPORT std::vector loadTileset(const std::string& file, int tile_px_w, int tile_px_h); +DFHACK_EXPORT std::vector loadTileset(const std::string& file, int tile_px_w, + int tile_px_h); /** * Get texpos by handle. @@ -39,15 +40,15 @@ DFHACK_EXPORT std::vector loadTileset(const std::string& file, int DFHACK_EXPORT long getTexposByHandle(TexposHandle handle); /** - * Call this on DFHack init and on every viewscreen change so we can reload - * and reindex textures as needed. + * Get texpos for static asset with index in tileset. */ -void init(DFHack::color_ostream& out); +DFHACK_EXPORT long getAsset(const std::string asset, size_t index = 0); /** - * Call this on DFHack init just once to setup interposed handlers. + * Call this on DFHack init just once to setup interposed handlers and + * init static assets. */ -void initDynamic(DFHack::color_ostream& out); +void init(DFHack::color_ostream& out); /** * Call this when DFHack is being unloaded. @@ -55,51 +56,5 @@ void initDynamic(DFHack::color_ostream& out); */ void cleanup(); -/** - * Get first texpos for the DFHack logo. This texpos and the next 11 make up the - * 4x3 grid of logo textures that can be displayed on the UI layer. - */ -DFHACK_EXPORT long getDfhackLogoTexposStart(); - -/** - * Get the first texpos for the UI pin tiles. Each are 2x2 grids. - */ -DFHACK_EXPORT long getGreenPinTexposStart(); -DFHACK_EXPORT long getRedPinTexposStart(); - -/** - * Get the first texpos for the DFHack icons. It's a 5x2 grid. - */ -DFHACK_EXPORT long getIconsTexposStart(); - -/** - * Get the first texpos for the on and off icons. It's a 2x1 grid. - */ -DFHACK_EXPORT long getOnOffTexposStart(); - -/** - * Get the first texpos for the pathable 32x32 sprites. It's a 2x1 grid. - */ -DFHACK_EXPORT long getMapPathableTexposStart(); - -/** - * Get the first texpos for the unsuspend 32x32 sprites. It's a 5x1 grid. - */ -DFHACK_EXPORT long getMapUnsuspendTexposStart(); - -/** - * Get the first texpos for the control panel icons. 10x2 grid. - */ -DFHACK_EXPORT long getControlPanelTexposStart(); - -/** - * Get the first texpos for the DFHack borders. Each is a 7x3 grid. - */ -DFHACK_EXPORT long getThinBordersTexposStart(); -DFHACK_EXPORT long getMediumBordersTexposStart(); -DFHACK_EXPORT long getBoldBordersTexposStart(); -DFHACK_EXPORT long getPanelBordersTexposStart(); -DFHACK_EXPORT long getWindowBordersTexposStart(); - -} -} +} // namespace Textures +} // namespace DFHack diff --git a/library/lua/gui.lua b/library/lua/gui.lua index ca3b212f0..c511f1005 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -913,10 +913,10 @@ local BASE_FRAME = { } local function make_frame(name, double_line) - local texpos = dfhack.textures['get'..name..'BordersTexposStart']() local tp = function(offset) + local texpos = dfhack.textures.getAsset('hack/data/art/border-'..name:lower()..'.png', offset) if texpos == -1 then return nil end - return texpos + offset + return texpos end local frame = copyall(BASE_FRAME) @@ -951,8 +951,40 @@ BOLD_FRAME = FRAME_BOLD INTERIOR_FRAME = FRAME_INTERIOR INTERIOR_MEDIUM_FRAME = FRAME_INTERIOR_MEDIUM +-- for compatibility with dynamic textures +local function choose_frame_style(style) + if style == FRAME_WINDOW then return make_frame('Window', true) end + if style == FRAME_PANEL then return make_frame('Panel', true) end + if style == FRAME_MEDIUM then return make_frame('Medium', true) end + if style == FRAME_BOLD then return make_frame('Bold', true) end + if style == FRAME_INTERIOR then + local frame = make_frame('Thin', true) + frame.signature_pen = false + return frame + end + if style == FRAME_INTERIOR_MEDIUM then + local frame = make_frame('Medium', true) + frame.signature_pen = false + return frame + end + if style == GREY_LINE_FRAME then return make_frame('Panel', true) end + if style == WINDOW_FRAME then return make_frame('Window', true) end + if style == PANEL_FRAME then return make_frame('Panel', true) end + if style == MEDIUM_FRAME then return make_frame('Medium', true) end + if style == INTERIOR_FRAME then + local frame = make_frame('Thin', true) + frame.signature_pen = false + return frame + end + if style == INTERIOR_MEDIUM_FRAME then + local frame = make_frame('Medium', true) + frame.signature_pen = false + return frame + end +end -function paint_frame(dc,rect,style,title,inactive,pause_forced,resizable) +function paint_frame(dc, rect, style, title, inactive, pause_forced, resizable) + style = choose_frame_style(style) local pen = style.frame_pen local x1,y1,x2,y2 = dc.x1+rect.x1, dc.y1+rect.y1, dc.x1+rect.x2, dc.y1+rect.y2 dscreen.paintTile(style.lt_frame_pen or pen, x1, y1) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index ec9fa41f1..712375a70 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -13,8 +13,8 @@ #include "df/enabler.h" #include "df/viewscreen_adopt_regionst.h" #include "df/viewscreen_loadgamest.h" -#include "df/viewscreen_new_regionst.h" #include "df/viewscreen_new_arenast.h" +#include "df/viewscreen_new_regionst.h" using df::global::enabler; using namespace DFHack; @@ -24,22 +24,6 @@ namespace DFHack { DBG_DECLARE(core, textures, DebugCategory::LINFO); } -static bool g_loaded = false; -static long g_num_dfhack_textures = 0; -static long g_dfhack_logo_texpos_start = -1; -static long g_green_pin_texpos_start = -1; -static long g_red_pin_texpos_start = -1; -static long g_icons_texpos_start = -1; -static long g_on_off_texpos_start = -1; -static long g_pathable_texpos_start = -1; -static long g_unsuspend_texpos_start = -1; -static long g_control_panel_texpos_start = -1; -static long g_thin_borders_texpos_start = -1; -static long g_medium_borders_texpos_start = -1; -static long g_bold_borders_texpos_start = -1; -static long g_panel_borders_texpos_start = -1; -static long g_window_borders_texpos_start = -1; - static std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_surface; static std::mutex g_adding_mutex; @@ -47,6 +31,16 @@ static std::mutex g_adding_mutex; const uint32_t TILE_WIDTH_PX = 8; const uint32_t TILE_HEIGHT_PX = 12; +static std::vector empty{}; +static std::unordered_map> g_static_assets{ + {"hack/data/art/dfhack.png", empty}, {"hack/data/art/green-pin.png", empty}, + {"hack/data/art/red-pin.png", empty}, {"hack/data/art/icons.png", empty}, + {"hack/data/art/on-off.png", empty}, {"hack/data/art/pathable.png", empty}, + {"hack/data/art/unsuspend.png", empty}, {"hack/data/art/control-panel.png", empty}, + {"hack/data/art/border-thin.png", empty}, {"hack/data/art/border-medium.png", empty}, + {"hack/data/art/border-bold.png", empty}, {"hack/data/art/border-panel.png", empty}, + {"hack/data/art/border-window.png", empty}}; + // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -55,34 +49,40 @@ const uint32_t TILE_HEIGHT_PX = 12; // It uses the same pixel format (RGBA, R at lowest address) regardless of // hardware. SDL_Surface* canonicalize_format(SDL_Surface* src) { - SDL_PixelFormat fmt; - fmt.palette = NULL; - fmt.BitsPerPixel = 32; - fmt.BytesPerPixel = 4; - fmt.Rloss = fmt.Gloss = fmt.Bloss = fmt.Aloss = 0; + SDL_PixelFormat fmt; + fmt.palette = NULL; + fmt.BitsPerPixel = 32; + fmt.BytesPerPixel = 4; + fmt.Rloss = fmt.Gloss = fmt.Bloss = fmt.Aloss = 0; #if SDL_BYTEORDER == SDL_BIG_ENDIAN - fmt.Rshift = 24; fmt.Gshift = 16; fmt.Bshift = 8; fmt.Ashift = 0; + fmt.Rshift = 24; + fmt.Gshift = 16; + fmt.Bshift = 8; + fmt.Ashift = 0; #else - fmt.Rshift = 0; fmt.Gshift = 8; fmt.Bshift = 16; fmt.Ashift = 24; + fmt.Rshift = 0; + fmt.Gshift = 8; + fmt.Bshift = 16; + fmt.Ashift = 24; #endif - fmt.Rmask = 255 << fmt.Rshift; - fmt.Gmask = 255 << fmt.Gshift; - fmt.Bmask = 255 << fmt.Bshift; - fmt.Amask = 255 << fmt.Ashift; - - SDL_Surface* tgt = DFSDL_ConvertSurface(src, &fmt, SDL_SWSURFACE); - DFSDL_FreeSurface(src); - for (int x = 0; x < tgt->w; ++x) { - for (int y = 0; y < tgt->h; ++y) { - Uint8* p = (Uint8*)tgt->pixels + y * tgt->pitch + x * 4; - if (p[3] == 0) { - for (int c = 0; c < 3; c++) { - p[c] = 0; - } - } - } - } - return tgt; + fmt.Rmask = 255 << fmt.Rshift; + fmt.Gmask = 255 << fmt.Gshift; + fmt.Bmask = 255 << fmt.Bshift; + fmt.Amask = 255 << fmt.Ashift; + + SDL_Surface* tgt = DFSDL_ConvertSurface(src, &fmt, SDL_SWSURFACE); + DFSDL_FreeSurface(src); + for (int x = 0; x < tgt->w; ++x) { + for (int y = 0; y < tgt->h; ++y) { + Uint8* p = (Uint8*)tgt->pixels + y * tgt->pitch + x * 4; + if (p[3] == 0) { + for (int c = 0; c < 3; c++) { + p[c] = 0; + } + } + } + } + return tgt; } // register surface in texture raws, get a texpos @@ -97,7 +97,7 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { if (!surface) return 0; // should be some error, i guess - auto handle = reinterpret_cast(surface); + auto handle = reinterpret_cast(surface); // not the best way? but cheap g_handle_to_surface.emplace(handle, surface); surface->refcount++; // prevent destruct on next FreeSurface by game auto texpos = add_texture(surface); @@ -121,10 +121,10 @@ std::vector Textures::loadTileset(const std::string& file, int dimy = surface->h / tile_px_h; for (int y = 0; y < dimy; y++) { for (int x = 0; x < dimx; x++) { - SDL_Surface* tile = DFSDL_CreateRGBSurface(0, tile_px_w, tile_px_h, 32, - surface->format->Rmask, surface->format->Gmask, - surface->format->Bmask, surface->format->Amask); - SDL_Rect vp{ tile_px_w * x, tile_px_h * y, tile_px_w, tile_px_h }; + SDL_Surface* tile = DFSDL_CreateRGBSurface( + 0, tile_px_w, tile_px_h, 32, surface->format->Rmask, surface->format->Gmask, + surface->format->Bmask, surface->format->Amask); + SDL_Rect vp{tile_px_w * x, tile_px_h * y, tile_px_w, tile_px_h}; DFSDL_UpperBlit(surface, &vp, tile, NULL); auto handle = Textures::loadTexture(tile); handles.push_back(handle); @@ -154,6 +154,14 @@ long Textures::getTexposByHandle(TexposHandle handle) { return -1; } +long Textures::getAsset(const std::string asset, size_t index) { + if (!g_static_assets.contains(asset)) + return -1; + if (g_static_assets[asset].size() <= index) + return -1; + return Textures::getTexposByHandle(g_static_assets[asset][index]); +} + static void reset_texpos() { g_handle_to_texpos.clear(); } @@ -190,7 +198,7 @@ struct tracking_stage_adopt_region : df::viewscreen_adopt_regionst { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { this->m_cur_step = this->cur_step; - if (this->m_cur_step == df::viewscreen_adopt_regionst::T_cur_step::ProcessingRawData) + if (this->m_cur_step == 2) reset_texpos(); } INTERPOSE_NEXT(logic)(); @@ -208,7 +216,7 @@ struct tracking_stage_load_region : df::viewscreen_loadgamest { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { this->m_cur_step = this->cur_step; - if (this->m_cur_step == df::viewscreen_loadgamest::T_cur_step::ProcessingRawData) + if (this->m_cur_step == 1) reset_texpos(); } INTERPOSE_NEXT(logic)(); @@ -251,180 +259,19 @@ static void uninstall_reset_point() { INTERPOSE_HOOK(tracking_stage_new_arena, logic).remove(); } -static size_t load_tiles_from_image(color_ostream& out, const char* fname, - long* texpos_start, - int tile_w = TILE_WIDTH_PX, - int tile_h = TILE_HEIGHT_PX) { - SDL_Surface* s = DFIMG_Load(fname); - if (!s) { - out.printerr("unable to load textures from '%s'\n", fname); - return 0; - } +void Textures::init(color_ostream& out) { + install_reset_point(); + DEBUG(textures, out).print("dynamic texture loading ready"); - s = canonicalize_format(s); - int dimx = s->w / tile_w; - int dimy = s->h / tile_h; - long count = 0; - for (int y = 0; y < dimy; y++) { - for (int x = 0; x < dimx; x++) { - SDL_Surface* tile = DFSDL_CreateRGBSurface(0, // SDL_SWSURFACE - tile_w, tile_h, 32, - s->format->Rmask, s->format->Gmask, s->format->Bmask, - s->format->Amask); - SDL_Rect vp; - vp.x = tile_w * x; - vp.y = tile_h * y; - vp.w = tile_w; - vp.h = tile_h; - DFSDL_UpperBlit(s, &vp, tile, NULL); - if (!count++) - *texpos_start = enabler->textures.raws.size(); - enabler->textures.raws.push_back(tile); - } + for (auto& [key, value] : g_static_assets) { + g_static_assets[key] = Textures::loadTileset(key); } - DFSDL_FreeSurface(s); - DEBUG(textures,out).print("loaded %ld textures from '%s'\n", count, fname); - return count; + DEBUG(textures, out).print("assets loaded"); } -void Textures::initDynamic(color_ostream& out) { - install_reset_point(); - DEBUG(textures, out).print("dynamic texture reset points installed"); -} - -// DFHack could conceivably be loaded at any time, so we need to be able to -// handle loading textures before or after a world is loaded. -// If a world is already loaded, then append our textures to the raws. they'll -// be freed when the world is unloaded and we'll reload when we get to the title -// screen. If it's pre-world, append our textures and then adjust the "init" -// texture count so our textures will no longer be freed when worlds are -// unloaded. -// -void Textures::init(color_ostream& out) { - if (!enabler) - return; - - auto& textures = enabler->textures; - long num_textures = textures.raws.size(); - if (num_textures <= g_dfhack_logo_texpos_start) - g_loaded = false; - - if (g_loaded) - return; - - bool is_pre_world = num_textures == textures.init_texture_size; - - g_num_dfhack_textures = load_tiles_from_image(out, "hack/data/art/dfhack.png", - &g_dfhack_logo_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/green-pin.png", - &g_green_pin_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/red-pin.png", - &g_red_pin_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/icons.png", - &g_icons_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/on-off.png", - &g_on_off_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/pathable.png", - &g_pathable_texpos_start, 32, 32); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/unsuspend.png", - &g_unsuspend_texpos_start, 32, 32); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/control-panel.png", - &g_control_panel_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-thin.png", - &g_thin_borders_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-medium.png", - &g_medium_borders_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-bold.png", - &g_bold_borders_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-panel.png", - &g_panel_borders_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-window.png", - &g_window_borders_texpos_start); - - DEBUG(textures,out).print("loaded %ld textures\n", g_num_dfhack_textures); - - if (is_pre_world) - textures.init_texture_size += g_num_dfhack_textures; - - // NOTE: when GL modes are supported, we'll have to re-upload textures here - - g_loaded = true; -} - -// It's ok to leave NULLs in the raws list (according to usage in g_src) void Textures::cleanup() { reset_texpos(); reset_surface(); uninstall_reset_point(); - - if (!g_loaded) - return; - - auto& textures = enabler->textures; - auto& raws = textures.raws; - size_t texpos_end = g_dfhack_logo_texpos_start + g_num_dfhack_textures - 1; - for (size_t idx = g_dfhack_logo_texpos_start; idx <= texpos_end; ++idx) { - DFSDL_FreeSurface((SDL_Surface *)raws[idx]); - raws[idx] = NULL; - } - - if (g_dfhack_logo_texpos_start == textures.init_texture_size - g_num_dfhack_textures) - textures.init_texture_size -= g_num_dfhack_textures; - - g_loaded = false; - g_num_dfhack_textures = 0; - g_dfhack_logo_texpos_start = -1; -} - -long Textures::getDfhackLogoTexposStart() { - return g_dfhack_logo_texpos_start; -} - -long Textures::getGreenPinTexposStart() { - return g_green_pin_texpos_start; -} - -long Textures::getRedPinTexposStart() { - return g_red_pin_texpos_start; -} - -long Textures::getIconsTexposStart() { - return g_icons_texpos_start; -} - -long Textures::getOnOffTexposStart() { - return g_on_off_texpos_start; -} - -long Textures::getMapPathableTexposStart() { - return g_pathable_texpos_start; -} - -long Textures::getMapUnsuspendTexposStart() { - return g_unsuspend_texpos_start; -} - -long Textures::getControlPanelTexposStart() { - return g_control_panel_texpos_start; -} - -long Textures::getThinBordersTexposStart() { - return g_thin_borders_texpos_start; -} - -long Textures::getMediumBordersTexposStart() { - return g_medium_borders_texpos_start; -} - -long Textures::getBoldBordersTexposStart() { - return g_bold_borders_texpos_start; -} - -long Textures::getPanelBordersTexposStart() { - return g_panel_borders_texpos_start; -} - -long Textures::getWindowBordersTexposStart() { - return g_window_borders_texpos_start; } diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index e69a4c210..52db6c893 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -9,29 +9,30 @@ MINI_TEXT_PEN, MINI_TEXT_HPEN, MINI_BUTT_PEN, MINI_BUTT_HPEN = nil, nil, nil, ni local to_pen = dfhack.pen.parse -local tp = function(base, offset) - if base == -1 then return nil end - return base + offset +local tp = function(asset, offset) + local texpos = dfhack.textures.getAsset(asset, offset) + if texpos == -1 then return nil end + return texpos end function reload_pens() GOOD_TILE_PEN = to_pen{ch='o', fg=COLOR_GREEN, tile=dfhack.screen.findGraphicsTile('CURSORS', 1, 2)} BAD_TILE_PEN = to_pen{ch='X', fg=COLOR_RED, tile=dfhack.screen.findGraphicsTile('CURSORS', 3, 0)} - local tb_texpos = dfhack.textures.getThinBordersTexposStart() - VERT_TOP_PEN = to_pen{tile=tp(tb_texpos, 10), ch=194, fg=COLOR_GREY, bg=COLOR_BLACK} - VERT_MID_PEN = to_pen{tile=tp(tb_texpos, 4), ch=179, fg=COLOR_GREY, bg=COLOR_BLACK} - VERT_BOT_PEN = to_pen{tile=tp(tb_texpos, 11), ch=193, fg=COLOR_GREY, bg=COLOR_BLACK} + local tb = "hack/data/art/border-thin.png" + VERT_TOP_PEN = to_pen { tile = tp(tb, 10), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_MID_PEN = to_pen { tile = tp(tb, 4), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_BOT_PEN = to_pen { tile = tp(tb, 11), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } - local mb_texpos = dfhack.textures.getMediumBordersTexposStart() - HORI_LEFT_PEN = to_pen{tile=tp(mb_texpos, 12), ch=195, fg=COLOR_GREY, bg=COLOR_BLACK} - HORI_MID_PEN = to_pen{tile=tp(mb_texpos, 5), ch=196, fg=COLOR_GREY, bg=COLOR_BLACK} - HORI_RIGHT_PEN = to_pen{tile=tp(mb_texpos, 13), ch=180, fg=COLOR_GREY, bg=COLOR_BLACK} + local mb = "hack/data/art/border-medium.png" + HORI_LEFT_PEN = to_pen { tile = tp(mb, 12), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_MID_PEN = to_pen { tile = tp(mb, 5), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_RIGHT_PEN = to_pen { tile = tp(mb, 13), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } - local cp_texpos = dfhack.textures.getControlPanelTexposStart() - BUTTON_START_PEN = to_pen{tile=tp(cp_texpos, 13), ch='[', fg=COLOR_YELLOW} - BUTTON_END_PEN = to_pen{tile=tp(cp_texpos, 15), ch=']', fg=COLOR_YELLOW} - SELECTED_ITEM_PEN = to_pen{tile=tp(cp_texpos, 9), ch=string.char(251), fg=COLOR_YELLOW} + local cp = "hack/data/art/control-panel.png" + BUTTON_START_PEN = to_pen { tile = tp(cp, 13), ch = '[', fg = COLOR_YELLOW } + BUTTON_END_PEN = to_pen { tile = tp(cp, 15), ch = ']', fg = COLOR_YELLOW } + SELECTED_ITEM_PEN = to_pen { tile = tp(cp, 9), ch = string.char(251), fg = COLOR_YELLOW } MINI_TEXT_PEN = to_pen{fg=COLOR_BLACK, bg=COLOR_GREY} MINI_TEXT_HPEN = to_pen{fg=COLOR_BLACK, bg=COLOR_WHITE} diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 373b2945f..f58d8322a 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -68,28 +68,30 @@ end local dscreen = dfhack.screen function HotspotMenuWidget:onRenderBody(dc) - local tpos = dfhack.textures.getDfhackLogoTexposStart() local x, y = dc.x, dc.y + local tp = function(offset) + return dfhack.textures.getAsset("hack/data/art/dfhack.png", offset) + end - if tpos == -1 then - dscreen.paintString(COLOR_WHITE, x, y+0, '!DF!') - dscreen.paintString(COLOR_WHITE, x, y+1, '!Ha!') - dscreen.paintString(COLOR_WHITE, x, y+2, '!ck!') + if tp(0) == -1 then + dscreen.paintString(COLOR_WHITE, x, y + 0, '!DF!') + dscreen.paintString(COLOR_WHITE, x, y + 1, '!Ha!') + dscreen.paintString(COLOR_WHITE, x, y + 2, '!ck!') else - dscreen.paintTile(COLOR_WHITE, x+0, y+0, '!', tpos+0) - dscreen.paintTile(COLOR_WHITE, x+1, y+0, 'D', tpos+1) - dscreen.paintTile(COLOR_WHITE, x+2, y+0, 'F', tpos+2) - dscreen.paintTile(COLOR_WHITE, x+3, y+0, '!', tpos+3) - - dscreen.paintTile(COLOR_WHITE, x+0, y+1, '!', tpos+4) - dscreen.paintTile(COLOR_WHITE, x+1, y+1, 'H', tpos+5) - dscreen.paintTile(COLOR_WHITE, x+2, y+1, 'a', tpos+6) - dscreen.paintTile(COLOR_WHITE, x+3, y+1, '!', tpos+7) - - dscreen.paintTile(COLOR_WHITE, x+0, y+2, '!', tpos+8) - dscreen.paintTile(COLOR_WHITE, x+1, y+2, 'c', tpos+9) - dscreen.paintTile(COLOR_WHITE, x+2, y+2, 'k', tpos+10) - dscreen.paintTile(COLOR_WHITE, x+3, y+2, '!', tpos+11) + dscreen.paintTile(COLOR_WHITE, x + 0, y + 0, '!', tp(0)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 0, 'D', tp(1)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 0, 'F', tp(2)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 0, '!', tp(3)) + + dscreen.paintTile(COLOR_WHITE, x + 0, y + 1, '!', tp(4)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 1, 'H', tp(5)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 1, 'a', tp(6)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 1, '!', tp(7)) + + dscreen.paintTile(COLOR_WHITE, x + 0, y + 2, '!', tp(8)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 2, 'c', tp(9)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 2, 'k', tp(10)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 2, '!', tp(11)) end end diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index f60469489..c0c49c470 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -44,10 +44,10 @@ static void paintScreenPathable(df::coord target, bool show_hidden = false) { long pathable_tile_texpos = init->load_bar_texpos[1]; long unpathable_tile_texpos = init->load_bar_texpos[4]; - long on_off_texpos = Textures::getMapPathableTexposStart(); + long on_off_texpos = Textures::getAsset("hack/data/art/pathable.png", 0); if (on_off_texpos > 0) { - pathable_tile_texpos = on_off_texpos + 0; - unpathable_tile_texpos = on_off_texpos + 1; + pathable_tile_texpos = on_off_texpos; + unpathable_tile_texpos = Textures::getAsset("hack/data/art/pathable.png", 1); } auto dims = Gui::getDwarfmodeViewDims().map(); From b20889e694612a1dc374fee9ed99c05211c1bbd3 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sat, 12 Aug 2023 16:34:33 +0300 Subject: [PATCH 06/21] minor refactor for lua switch --- library/lua/gui.lua | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index c511f1005..aaca5b849 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -953,30 +953,18 @@ INTERIOR_MEDIUM_FRAME = FRAME_INTERIOR_MEDIUM -- for compatibility with dynamic textures local function choose_frame_style(style) - if style == FRAME_WINDOW then return make_frame('Window', true) end - if style == FRAME_PANEL then return make_frame('Panel', true) end - if style == FRAME_MEDIUM then return make_frame('Medium', true) end - if style == FRAME_BOLD then return make_frame('Bold', true) end - if style == FRAME_INTERIOR then - local frame = make_frame('Thin', true) - frame.signature_pen = false - return frame + if style == FRAME_WINDOW or style == WINDOW_FRAME then return make_frame('Window', true) end + if style == FRAME_PANEL or style == GREY_LINE_FRAME or style == PANEL_FRAME then + return make_frame('Panel', true) end - if style == FRAME_INTERIOR_MEDIUM then - local frame = make_frame('Medium', true) - frame.signature_pen = false - return frame - end - if style == GREY_LINE_FRAME then return make_frame('Panel', true) end - if style == WINDOW_FRAME then return make_frame('Window', true) end - if style == PANEL_FRAME then return make_frame('Panel', true) end - if style == MEDIUM_FRAME then return make_frame('Medium', true) end - if style == INTERIOR_FRAME then + if style == FRAME_MEDIUM or style == MEDIUM_FRAME then return make_frame('Medium', true) end + if style == FRAME_BOLD then return make_frame('Bold', true) end + if style == FRAME_INTERIOR or style == INTERIOR_FRAME then local frame = make_frame('Thin', true) frame.signature_pen = false return frame end - if style == INTERIOR_MEDIUM_FRAME then + if style == FRAME_INTERIOR_MEDIUM or style == INTERIOR_MEDIUM_FRAME then local frame = make_frame('Medium', true) frame.signature_pen = false return frame From 46a3454fee59f27676b43d559c2ce62a59a9d0b7 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sat, 12 Aug 2023 17:00:07 +0300 Subject: [PATCH 07/21] type alias for gcc --- library/include/modules/Textures.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 9569a257a..4d20302cc 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -8,7 +8,7 @@ #include -typedef typename void* TexposHandle; +typedef void* TexposHandle; namespace DFHack { From 687bd82542e32c111fb582e06bc8c68fa6ffc45b Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sat, 12 Aug 2023 20:05:15 +0300 Subject: [PATCH 08/21] pathable & unsuspend specific tile size --- library/modules/Textures.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 712375a70..4df928684 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -264,7 +264,13 @@ void Textures::init(color_ostream& out) { DEBUG(textures, out).print("dynamic texture loading ready"); for (auto& [key, value] : g_static_assets) { - g_static_assets[key] = Textures::loadTileset(key); + auto tile_w = TILE_WIDTH_PX; + auto tile_h = TILE_HEIGHT_PX; + if (key == "hack/data/art/pathable.png" || key == "hack/data/art/unsuspend.png") { + tile_w = 32; + tile_h = 32; + } + g_static_assets[key] = Textures::loadTileset(key, tile_w, tile_h); } DEBUG(textures, out).print("assets loaded"); From 4bc3a9b552614109f88cc80cfd8a241a1d53be55 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 13 Aug 2023 07:36:39 +0300 Subject: [PATCH 09/21] single quotes --- plugins/lua/buildingplan/pens.lua | 6 +++--- plugins/lua/hotkeys.lua | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index 52db6c893..30ce478d8 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -19,17 +19,17 @@ function reload_pens() GOOD_TILE_PEN = to_pen{ch='o', fg=COLOR_GREEN, tile=dfhack.screen.findGraphicsTile('CURSORS', 1, 2)} BAD_TILE_PEN = to_pen{ch='X', fg=COLOR_RED, tile=dfhack.screen.findGraphicsTile('CURSORS', 3, 0)} - local tb = "hack/data/art/border-thin.png" + local tb = 'hack/data/art/border-thin.png' VERT_TOP_PEN = to_pen { tile = tp(tb, 10), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } VERT_MID_PEN = to_pen { tile = tp(tb, 4), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } VERT_BOT_PEN = to_pen { tile = tp(tb, 11), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } - local mb = "hack/data/art/border-medium.png" + local mb = 'hack/data/art/border-medium.png' HORI_LEFT_PEN = to_pen { tile = tp(mb, 12), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } HORI_MID_PEN = to_pen { tile = tp(mb, 5), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } HORI_RIGHT_PEN = to_pen { tile = tp(mb, 13), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } - local cp = "hack/data/art/control-panel.png" + local cp = 'hack/data/art/control-panel.png' BUTTON_START_PEN = to_pen { tile = tp(cp, 13), ch = '[', fg = COLOR_YELLOW } BUTTON_END_PEN = to_pen { tile = tp(cp, 15), ch = ']', fg = COLOR_YELLOW } SELECTED_ITEM_PEN = to_pen { tile = tp(cp, 9), ch = string.char(251), fg = COLOR_YELLOW } diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index f58d8322a..e2bef331b 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -70,7 +70,7 @@ local dscreen = dfhack.screen function HotspotMenuWidget:onRenderBody(dc) local x, y = dc.x, dc.y local tp = function(offset) - return dfhack.textures.getAsset("hack/data/art/dfhack.png", offset) + return dfhack.textures.getAsset('hack/data/art/dfhack.png', offset) end if tp(0) == -1 then From 20460feccad16c365b5901ed2823e158e4e1467f Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 13 Aug 2023 07:40:35 +0300 Subject: [PATCH 10/21] tiny refactor texpos methods --- library/lua/gui.lua | 3 +-- plugins/lua/buildingplan/pens.lua | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index aaca5b849..d9f826cd1 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -915,8 +915,7 @@ local BASE_FRAME = { local function make_frame(name, double_line) local tp = function(offset) local texpos = dfhack.textures.getAsset('hack/data/art/border-'..name:lower()..'.png', offset) - if texpos == -1 then return nil end - return texpos + return texpos >= 0 and texpos or nil end local frame = copyall(BASE_FRAME) diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index 30ce478d8..7e9b24300 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -11,8 +11,7 @@ local to_pen = dfhack.pen.parse local tp = function(asset, offset) local texpos = dfhack.textures.getAsset(asset, offset) - if texpos == -1 then return nil end - return texpos + return texpos >= 0 and texpos or nil end function reload_pens() From 22b0671038e60b1180649aadceb1e4a4b70868f5 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 13 Aug 2023 08:33:31 +0300 Subject: [PATCH 11/21] review 2 --- library/Core.cpp | 2 -- library/include/modules/Textures.h | 12 ++++--- library/modules/Textures.cpp | 55 ++++++++++++++++-------------- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 4950e848d..7576f892b 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2217,8 +2217,6 @@ void Core::onStateChange(color_ostream &out, state_change_event event) } } break; - case SC_VIEWSCREEN_CHANGED: - break; default: break; } diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 4d20302cc..9166e7607 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -6,9 +6,9 @@ #include "ColorText.h" #include "Export.h" -#include +struct SDL_Surface; -typedef void* TexposHandle; +typedef SDL_Surface* TexposHandle; namespace DFHack { @@ -19,6 +19,9 @@ namespace DFHack { */ namespace Textures { +const uint32_t TILE_WIDTH_PX = 8; +const uint32_t TILE_HEIGHT_PX = 12; + /** * Load texture and get handle. * Keep it to obtain valid texpos. @@ -29,8 +32,9 @@ DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); * Load tileset from image file. * Return vector of handles to obtain valid texposes. */ -DFHACK_EXPORT std::vector loadTileset(const std::string& file, int tile_px_w, - int tile_px_h); +DFHACK_EXPORT std::vector loadTileset(const std::string& file, + int tile_px_w = TILE_WIDTH_PX, + int tile_px_h = TILE_HEIGHT_PX); /** * Get texpos by handle. diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 4df928684..0eb4e442d 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -16,30 +16,38 @@ #include "df/viewscreen_new_arenast.h" #include "df/viewscreen_new_regionst.h" +#include + using df::global::enabler; using namespace DFHack; using namespace DFHack::DFSDL; namespace DFHack { - DBG_DECLARE(core, textures, DebugCategory::LINFO); +DBG_DECLARE(core, textures, DebugCategory::LINFO); } static std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_surface; static std::mutex g_adding_mutex; -const uint32_t TILE_WIDTH_PX = 8; -const uint32_t TILE_HEIGHT_PX = 12; - static std::vector empty{}; -static std::unordered_map> g_static_assets{ - {"hack/data/art/dfhack.png", empty}, {"hack/data/art/green-pin.png", empty}, - {"hack/data/art/red-pin.png", empty}, {"hack/data/art/icons.png", empty}, - {"hack/data/art/on-off.png", empty}, {"hack/data/art/pathable.png", empty}, - {"hack/data/art/unsuspend.png", empty}, {"hack/data/art/control-panel.png", empty}, - {"hack/data/art/border-thin.png", empty}, {"hack/data/art/border-medium.png", empty}, - {"hack/data/art/border-bold.png", empty}, {"hack/data/art/border-panel.png", empty}, - {"hack/data/art/border-window.png", empty}}; +// handle, tile width px, tile height px +static std::tuple, int, int> basic{empty, Textures::TILE_WIDTH_PX, + Textures::TILE_HEIGHT_PX}; +static std::unordered_map, int, int>> + g_static_assets{{"hack/data/art/dfhack.png", basic}, + {"hack/data/art/green-pin.png", basic}, + {"hack/data/art/red-pin.png", basic}, + {"hack/data/art/icons.png", basic}, + {"hack/data/art/on-off.png", basic}, + {"hack/data/art/pathable.png", std::make_tuple(empty, 32, 32)}, + {"hack/data/art/unsuspend.png", std::make_tuple(empty, 32, 32)}, + {"hack/data/art/control-panel.png", basic}, + {"hack/data/art/border-thin.png", basic}, + {"hack/data/art/border-medium.png", basic}, + {"hack/data/art/border-bold.png", basic}, + {"hack/data/art/border-panel.png", basic}, + {"hack/data/art/border-window.png", basic}}; // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set @@ -97,7 +105,7 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { if (!surface) return 0; // should be some error, i guess - auto handle = reinterpret_cast(surface); // not the best way? but cheap + auto handle = surface; g_handle_to_surface.emplace(handle, surface); surface->refcount++; // prevent destruct on next FreeSurface by game auto texpos = add_texture(surface); @@ -105,9 +113,8 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { return handle; } -std::vector Textures::loadTileset(const std::string& file, - int tile_px_w = TILE_WIDTH_PX, - int tile_px_h = TILE_HEIGHT_PX) { +std::vector Textures::loadTileset(const std::string& file, int tile_px_w, + int tile_px_h) { std::vector handles{}; SDL_Surface* surface = DFIMG_Load(file.c_str()); @@ -157,9 +164,10 @@ long Textures::getTexposByHandle(TexposHandle handle) { long Textures::getAsset(const std::string asset, size_t index) { if (!g_static_assets.contains(asset)) return -1; - if (g_static_assets[asset].size() <= index) + auto handles = std::get<0>(g_static_assets[asset]); + if (handles.size() <= index) return -1; - return Textures::getTexposByHandle(g_static_assets[asset][index]); + return Textures::getTexposByHandle(handles[index]); } static void reset_texpos() { @@ -264,13 +272,10 @@ void Textures::init(color_ostream& out) { DEBUG(textures, out).print("dynamic texture loading ready"); for (auto& [key, value] : g_static_assets) { - auto tile_w = TILE_WIDTH_PX; - auto tile_h = TILE_HEIGHT_PX; - if (key == "hack/data/art/pathable.png" || key == "hack/data/art/unsuspend.png") { - tile_w = 32; - tile_h = 32; - } - g_static_assets[key] = Textures::loadTileset(key, tile_w, tile_h); + auto tile_w = std::get<1>(value); + auto tile_h = std::get<2>(value); + g_static_assets[key] = + std::make_tuple(Textures::loadTileset(key, tile_w, tile_h), tile_w, tile_h); } DEBUG(textures, out).print("assets loaded"); From 1409af67de7cc818ae3c29def1c3d813f3c7ce1a Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 13 Aug 2023 20:09:12 +0300 Subject: [PATCH 12/21] expose api to lua --- library/LuaApi.cpp | 18 +++++++++++++++- library/include/modules/Textures.h | 2 +- library/modules/Textures.cpp | 7 +++---- plugins/lua/hotkeys.lua | 33 +++++++++++++++--------------- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 61a7eb83d..095d432ee 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1709,8 +1709,24 @@ static const luaL_Reg dfhack_job_funcs[] = { /***** Textures module *****/ +static int textures_loadTileset(lua_State *state) +{ + std::string file = luaL_checkstring(state, 1); + auto tile_w = luaL_checkint(state, 2); + auto tile_h = luaL_checkint(state, 3); + auto handles = Textures::loadTileset(file, tile_w, tile_h); + Lua::PushVector(state, handles); + return 1; +} + static const LuaWrapper::FunctionReg dfhack_textures_module[] = { WRAPM(Textures, getAsset), + WRAPM(Textures, getTexposByHandle), + { NULL, NULL } +}; + +static const luaL_Reg dfhack_textures_funcs[] = { + { "loadTileset", textures_loadTileset }, { NULL, NULL } }; @@ -3680,7 +3696,7 @@ void OpenDFHackApi(lua_State *state) luaL_setfuncs(state, dfhack_funcs, 0); OpenModule(state, "gui", dfhack_gui_module, dfhack_gui_funcs); OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs); - OpenModule(state, "textures", dfhack_textures_module); + OpenModule(state, "textures", dfhack_textures_module, dfhack_textures_funcs); OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs); OpenModule(state, "military", dfhack_military_module); OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs); diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 9166e7607..d8a256b2b 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -8,7 +8,7 @@ struct SDL_Surface; -typedef SDL_Surface* TexposHandle; +typedef uintptr_t TexposHandle; namespace DFHack { diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 0eb4e442d..10ccbf59d 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -35,8 +35,7 @@ static std::vector empty{}; static std::tuple, int, int> basic{empty, Textures::TILE_WIDTH_PX, Textures::TILE_HEIGHT_PX}; static std::unordered_map, int, int>> - g_static_assets{{"hack/data/art/dfhack.png", basic}, - {"hack/data/art/green-pin.png", basic}, + g_static_assets{{"hack/data/art/green-pin.png", basic}, {"hack/data/art/red-pin.png", basic}, {"hack/data/art/icons.png", basic}, {"hack/data/art/on-off.png", basic}, @@ -105,7 +104,7 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { if (!surface) return 0; // should be some error, i guess - auto handle = surface; + auto handle = reinterpret_cast(surface); g_handle_to_surface.emplace(handle, surface); surface->refcount++; // prevent destruct on next FreeSurface by game auto texpos = add_texture(surface); @@ -139,7 +138,7 @@ std::vector Textures::loadTileset(const std::string& file, int til } DFSDL_FreeSurface(surface); - DEBUG(textures).print("loaded %ld textures from '%s'\n", handles.size(), file.c_str()); + DEBUG(textures).print("loaded %i textures from '%s'\n", handles.size(), file.c_str()); return handles; } diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index e2bef331b..ce4342ea0 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -50,6 +50,7 @@ HotspotMenuWidget.ATTRS{ function HotspotMenuWidget:init() self.mouseover = false + self.textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) end function HotspotMenuWidget:overlay_onupdate() @@ -70,28 +71,28 @@ local dscreen = dfhack.screen function HotspotMenuWidget:onRenderBody(dc) local x, y = dc.x, dc.y local tp = function(offset) - return dfhack.textures.getAsset('hack/data/art/dfhack.png', offset) + return dfhack.textures.getTexposByHandle(self.textures[offset]) end - if tp(0) == -1 then + if tp(1) == -1 then dscreen.paintString(COLOR_WHITE, x, y + 0, '!DF!') dscreen.paintString(COLOR_WHITE, x, y + 1, '!Ha!') dscreen.paintString(COLOR_WHITE, x, y + 2, '!ck!') else - dscreen.paintTile(COLOR_WHITE, x + 0, y + 0, '!', tp(0)) - dscreen.paintTile(COLOR_WHITE, x + 1, y + 0, 'D', tp(1)) - dscreen.paintTile(COLOR_WHITE, x + 2, y + 0, 'F', tp(2)) - dscreen.paintTile(COLOR_WHITE, x + 3, y + 0, '!', tp(3)) - - dscreen.paintTile(COLOR_WHITE, x + 0, y + 1, '!', tp(4)) - dscreen.paintTile(COLOR_WHITE, x + 1, y + 1, 'H', tp(5)) - dscreen.paintTile(COLOR_WHITE, x + 2, y + 1, 'a', tp(6)) - dscreen.paintTile(COLOR_WHITE, x + 3, y + 1, '!', tp(7)) - - dscreen.paintTile(COLOR_WHITE, x + 0, y + 2, '!', tp(8)) - dscreen.paintTile(COLOR_WHITE, x + 1, y + 2, 'c', tp(9)) - dscreen.paintTile(COLOR_WHITE, x + 2, y + 2, 'k', tp(10)) - dscreen.paintTile(COLOR_WHITE, x + 3, y + 2, '!', tp(11)) + dscreen.paintTile(COLOR_WHITE, x + 0, y + 0, '!', tp(1)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 0, 'D', tp(2)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 0, 'F', tp(3)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 0, '!', tp(4)) + + dscreen.paintTile(COLOR_WHITE, x + 0, y + 1, '!', tp(5)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 1, 'H', tp(6)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 1, 'a', tp(7)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 1, '!', tp(8)) + + dscreen.paintTile(COLOR_WHITE, x + 0, y + 2, '!', tp(9)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 2, 'c', tp(10)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 2, 'k', tp(11)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 2, '!', tp(12)) end end From 91f4c3d561593f72839a7c63898929c06ded4f12 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 14 Aug 2023 08:17:57 +0300 Subject: [PATCH 13/21] mirgate preloaded assets to lua --- library/LuaApi.cpp | 1 - library/include/modules/Textures.h | 5 -- library/lua/gui.lua | 117 +++++++++++++++++------------ library/modules/Textures.cpp | 36 --------- plugins/lua/buildingplan/pens.lua | 28 +++---- plugins/lua/hotkeys.lua | 5 +- plugins/pathable.cpp | 7 +- 7 files changed, 89 insertions(+), 110 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 095d432ee..d61786feb 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1720,7 +1720,6 @@ static int textures_loadTileset(lua_State *state) } static const LuaWrapper::FunctionReg dfhack_textures_module[] = { - WRAPM(Textures, getAsset), WRAPM(Textures, getTexposByHandle), { NULL, NULL } }; diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index d8a256b2b..17cd6e2fc 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -43,11 +43,6 @@ DFHACK_EXPORT std::vector loadTileset(const std::string& file, */ DFHACK_EXPORT long getTexposByHandle(TexposHandle handle); -/** - * Get texpos for static asset with index in tileset. - */ -DFHACK_EXPORT long getAsset(const std::string asset, size_t index = 0); - /** * Call this on DFHack init just once to setup interposed handlers and * init static assets. diff --git a/library/lua/gui.lua b/library/lua/gui.lua index d9f826cd1..0176c998e 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -912,32 +912,77 @@ local BASE_FRAME = { paused_pen = to_pen{fg=COLOR_RED, bg=COLOR_BLACK}, } -local function make_frame(name, double_line) - local tp = function(offset) - local texpos = dfhack.textures.getAsset('hack/data/art/border-'..name:lower()..'.png', offset) - return texpos >= 0 and texpos or nil - end +local texpos_handles = { + green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), + red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12), + icons = dfhack.textures.loadTileset('hack/data/art/icons.png', 8, 12), + on_off = dfhack.textures.loadTileset('hack/data/art/on-off.png', 8, 12), + control_panel = dfhack.textures.loadTileset('hack/data/art/control-panel.png', 8, 12), + border_thin = dfhack.textures.loadTileset('hack/data/art/border-thin.png', 8, 12), + border_medium = dfhack.textures.loadTileset('hack/data/art/border-medium.png', 8, 12), + border_bold = dfhack.textures.loadTileset('hack/data/art/border-bold.png', 8, 12), + border_panel = dfhack.textures.loadTileset('hack/data/art/border-panel.png', 8, 12), + border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), +} +function tp_border_thin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_thin[offset]) +end +function tp_border_medium(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_medium[offset]) +end +function tp_border_bold(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_bold[offset]) +end +function tp_border_panel(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_panel[offset]) +end +function tp_border_window(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_window[offset]) +end +function tp_control_panel(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.control_panel[offset]) +end + +local function make_frame(tp, double_line) local frame = copyall(BASE_FRAME) - frame.t_frame_pen = to_pen{ tile=tp(1), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.l_frame_pen = to_pen{ tile=tp(7), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.b_frame_pen = to_pen{ tile=tp(15), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.r_frame_pen = to_pen{ tile=tp(9), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.lt_frame_pen = to_pen{ tile=tp(0), ch=double_line and 201 or 218, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.lb_frame_pen = to_pen{ tile=tp(14), ch=double_line and 200 or 192, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.rt_frame_pen = to_pen{ tile=tp(2), ch=double_line and 187 or 191, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.rb_frame_pen = to_pen{ tile=tp(16), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.t_frame_pen = to_pen{ tile=tp(2), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.l_frame_pen = to_pen{ tile=tp(8), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.b_frame_pen = to_pen{ tile=tp(16), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.r_frame_pen = to_pen{ tile=tp(10), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.lt_frame_pen = to_pen{ tile=tp(1), ch=double_line and 201 or 218, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.lb_frame_pen = to_pen{ tile=tp(15), ch=double_line and 200 or 192, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rt_frame_pen = to_pen{ tile=tp(3), ch=double_line and 187 or 191, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rb_frame_pen = to_pen{ tile=tp(17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } return frame end -FRAME_WINDOW = make_frame('Window', true) -FRAME_PANEL = make_frame('Panel', false) -FRAME_MEDIUM = make_frame('Medium', false) -FRAME_BOLD = make_frame('Bold', true) -FRAME_INTERIOR = make_frame('Thin', false) -FRAME_INTERIOR.signature_pen = false -FRAME_INTERIOR_MEDIUM = copyall(FRAME_MEDIUM) -FRAME_INTERIOR_MEDIUM.signature_pen = false +function FRAME_WINDOW(resizable) + local frame = make_frame(tp_border_window, true) + if not resizable then + frame.rb_frame_pen = to_pen{ tile=tp_border_panel(17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } + end + return frame +end +function FRAME_PANEL(resizable) + return make_frame(tp_border_panel, false) +end +function FRAME_MEDIUM(resizable) + return make_frame(tp_border_medium, false) +end +function FRAME_BOLD(resizable) + return make_frame(tp_border_bold, true) +end +function FRAME_INTERIOR(resizable) + local frame = make_frame(tp_border_thin, false) + frame.signature_pen = false + return frame +end +function FRAME_INTERIOR_MEDIUM(resizable) + local frame = make_frame(tp_border_medium, false) + frame.signature_pen = false + return frame +end -- for compatibility with pre-steam code GREY_LINE_FRAME = FRAME_PANEL @@ -950,38 +995,16 @@ BOLD_FRAME = FRAME_BOLD INTERIOR_FRAME = FRAME_INTERIOR INTERIOR_MEDIUM_FRAME = FRAME_INTERIOR_MEDIUM --- for compatibility with dynamic textures -local function choose_frame_style(style) - if style == FRAME_WINDOW or style == WINDOW_FRAME then return make_frame('Window', true) end - if style == FRAME_PANEL or style == GREY_LINE_FRAME or style == PANEL_FRAME then - return make_frame('Panel', true) - end - if style == FRAME_MEDIUM or style == MEDIUM_FRAME then return make_frame('Medium', true) end - if style == FRAME_BOLD then return make_frame('Bold', true) end - if style == FRAME_INTERIOR or style == INTERIOR_FRAME then - local frame = make_frame('Thin', true) - frame.signature_pen = false - return frame - end - if style == FRAME_INTERIOR_MEDIUM or style == INTERIOR_MEDIUM_FRAME then - local frame = make_frame('Medium', true) - frame.signature_pen = false - return frame - end -end - function paint_frame(dc, rect, style, title, inactive, pause_forced, resizable) - style = choose_frame_style(style) + if type(style) == 'function' then + style = style(resizable) + end local pen = style.frame_pen local x1,y1,x2,y2 = dc.x1+rect.x1, dc.y1+rect.y1, dc.x1+rect.x2, dc.y1+rect.y2 dscreen.paintTile(style.lt_frame_pen or pen, x1, y1) dscreen.paintTile(style.rt_frame_pen or pen, x2, y1) dscreen.paintTile(style.lb_frame_pen or pen, x1, y2) - local rb_frame_pen = style.rb_frame_pen - if rb_frame_pen == FRAME_WINDOW.rb_frame_pen and not resizable then - rb_frame_pen = FRAME_PANEL.rb_frame_pen - end - dscreen.paintTile(rb_frame_pen or pen, x2, y2) + dscreen.paintTile(style.rb_frame_pen or pen, x2, y2) dscreen.fillRect(style.t_frame_pen or style.h_frame_pen or pen,x1+1,y1,x2-1,y1) dscreen.fillRect(style.b_frame_pen or style.h_frame_pen or pen,x1+1,y2,x2-1,y2) dscreen.fillRect(style.l_frame_pen or style.v_frame_pen or pen,x1,y1+1,x1,y2-1) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 10ccbf59d..729bf0cae 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -30,24 +30,6 @@ static std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_surface; static std::mutex g_adding_mutex; -static std::vector empty{}; -// handle, tile width px, tile height px -static std::tuple, int, int> basic{empty, Textures::TILE_WIDTH_PX, - Textures::TILE_HEIGHT_PX}; -static std::unordered_map, int, int>> - g_static_assets{{"hack/data/art/green-pin.png", basic}, - {"hack/data/art/red-pin.png", basic}, - {"hack/data/art/icons.png", basic}, - {"hack/data/art/on-off.png", basic}, - {"hack/data/art/pathable.png", std::make_tuple(empty, 32, 32)}, - {"hack/data/art/unsuspend.png", std::make_tuple(empty, 32, 32)}, - {"hack/data/art/control-panel.png", basic}, - {"hack/data/art/border-thin.png", basic}, - {"hack/data/art/border-medium.png", basic}, - {"hack/data/art/border-bold.png", basic}, - {"hack/data/art/border-panel.png", basic}, - {"hack/data/art/border-window.png", basic}}; - // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -160,15 +142,6 @@ long Textures::getTexposByHandle(TexposHandle handle) { return -1; } -long Textures::getAsset(const std::string asset, size_t index) { - if (!g_static_assets.contains(asset)) - return -1; - auto handles = std::get<0>(g_static_assets[asset]); - if (handles.size() <= index) - return -1; - return Textures::getTexposByHandle(handles[index]); -} - static void reset_texpos() { g_handle_to_texpos.clear(); } @@ -269,15 +242,6 @@ static void uninstall_reset_point() { void Textures::init(color_ostream& out) { install_reset_point(); DEBUG(textures, out).print("dynamic texture loading ready"); - - for (auto& [key, value] : g_static_assets) { - auto tile_w = std::get<1>(value); - auto tile_h = std::get<2>(value); - g_static_assets[key] = - std::make_tuple(Textures::loadTileset(key, tile_w, tile_h), tile_w, tile_h); - } - - DEBUG(textures, out).print("assets loaded"); } void Textures::cleanup() { diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index 7e9b24300..d50ee4c75 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -1,5 +1,7 @@ local _ENV = mkmodule('plugins.buildingplan.pens') +local gui = require('gui') + GOOD_TILE_PEN, BAD_TILE_PEN = nil, nil VERT_TOP_PEN, VERT_MID_PEN, VERT_BOT_PEN = nil, nil, nil HORI_LEFT_PEN, HORI_MID_PEN, HORI_RIGHT_PEN = nil, nil, nil @@ -9,29 +11,21 @@ MINI_TEXT_PEN, MINI_TEXT_HPEN, MINI_BUTT_PEN, MINI_BUTT_HPEN = nil, nil, nil, ni local to_pen = dfhack.pen.parse -local tp = function(asset, offset) - local texpos = dfhack.textures.getAsset(asset, offset) - return texpos >= 0 and texpos or nil -end - function reload_pens() GOOD_TILE_PEN = to_pen{ch='o', fg=COLOR_GREEN, tile=dfhack.screen.findGraphicsTile('CURSORS', 1, 2)} BAD_TILE_PEN = to_pen{ch='X', fg=COLOR_RED, tile=dfhack.screen.findGraphicsTile('CURSORS', 3, 0)} - local tb = 'hack/data/art/border-thin.png' - VERT_TOP_PEN = to_pen { tile = tp(tb, 10), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_MID_PEN = to_pen { tile = tp(tb, 4), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_BOT_PEN = to_pen { tile = tp(tb, 11), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_TOP_PEN = to_pen { tile = gui.tp_border_thin(11), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_MID_PEN = to_pen { tile = gui.tp_border_thin(5), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_BOT_PEN = to_pen { tile = gui.tp_border_thin(12), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } - local mb = 'hack/data/art/border-medium.png' - HORI_LEFT_PEN = to_pen { tile = tp(mb, 12), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_MID_PEN = to_pen { tile = tp(mb, 5), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_RIGHT_PEN = to_pen { tile = tp(mb, 13), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_LEFT_PEN = to_pen { tile = gui.tp_border_medium(13), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_MID_PEN = to_pen { tile = gui.tp_border_medium(6), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_RIGHT_PEN = to_pen { tile = gui.tp_border_medium(14), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } - local cp = 'hack/data/art/control-panel.png' - BUTTON_START_PEN = to_pen { tile = tp(cp, 13), ch = '[', fg = COLOR_YELLOW } - BUTTON_END_PEN = to_pen { tile = tp(cp, 15), ch = ']', fg = COLOR_YELLOW } - SELECTED_ITEM_PEN = to_pen { tile = tp(cp, 9), ch = string.char(251), fg = COLOR_YELLOW } + BUTTON_START_PEN = to_pen { tile = gui.tp_control_panel(14), ch = '[', fg = COLOR_YELLOW } + BUTTON_END_PEN = to_pen { tile = gui.tp_control_panel(16), ch = ']', fg = COLOR_YELLOW } + SELECTED_ITEM_PEN = to_pen { tile = gui.tp_control_panel(10), ch = string.char(251), fg = COLOR_YELLOW } MINI_TEXT_PEN = to_pen{fg=COLOR_BLACK, bg=COLOR_GREY} MINI_TEXT_HPEN = to_pen{fg=COLOR_BLACK, bg=COLOR_WHITE} diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index ce4342ea0..728b8e9df 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -5,6 +5,8 @@ local helpdb = require('helpdb') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') +local textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) + local function get_command(cmdline) local first_word = cmdline:trim():split(' +')[1] if first_word:startswith(':') then first_word = first_word:sub(2) end @@ -50,7 +52,6 @@ HotspotMenuWidget.ATTRS{ function HotspotMenuWidget:init() self.mouseover = false - self.textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) end function HotspotMenuWidget:overlay_onupdate() @@ -71,7 +72,7 @@ local dscreen = dfhack.screen function HotspotMenuWidget:onRenderBody(dc) local x, y = dc.x, dc.y local tp = function(offset) - return dfhack.textures.getTexposByHandle(self.textures[offset]) + return dfhack.textures.getTexposByHandle(textures[offset]) end if tp(1) == -1 then diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index c0c49c470..12a69dd31 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -26,7 +26,10 @@ namespace DFHack { DBG_DECLARE(pathable, log, DebugCategory::LINFO); } +static std::vector textures; + DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { + textures = Textures::loadTileset("hack/data/art/pathable.png", 32, 32); return CR_OK; } @@ -44,10 +47,10 @@ static void paintScreenPathable(df::coord target, bool show_hidden = false) { long pathable_tile_texpos = init->load_bar_texpos[1]; long unpathable_tile_texpos = init->load_bar_texpos[4]; - long on_off_texpos = Textures::getAsset("hack/data/art/pathable.png", 0); + long on_off_texpos = Textures::getTexposByHandle(textures[0]); if (on_off_texpos > 0) { pathable_tile_texpos = on_off_texpos; - unpathable_tile_texpos = Textures::getAsset("hack/data/art/pathable.png", 1); + unpathable_tile_texpos = Textures::getTexposByHandle(textures[1]); } auto dims = Gui::getDwarfmodeViewDims().map(); From 900a2c65ba12a06c9b479748fd8b5d89bbf45a76 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 14 Aug 2023 09:02:37 +0300 Subject: [PATCH 14/21] invalid texpos is nil for lua --- library/LuaApi.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index d61786feb..174bedb56 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1719,13 +1719,25 @@ static int textures_loadTileset(lua_State *state) return 1; } +static int textures_getTexposByHandle(lua_State *state) +{ + auto handle = luaL_checkunsigned(state, 1); + auto texpos = Textures::getTexposByHandle(handle); + if (texpos == -1) { + lua_pushnil(state); + } else { + Lua::Push(state, texpos); + } + return 1; +} + static const LuaWrapper::FunctionReg dfhack_textures_module[] = { - WRAPM(Textures, getTexposByHandle), { NULL, NULL } }; static const luaL_Reg dfhack_textures_funcs[] = { { "loadTileset", textures_loadTileset }, + { "getTexposByHandle", textures_getTexposByHandle }, { NULL, NULL } }; From 0e725be04639db4f63c6e532fc70403d81f9b7da Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 14 Aug 2023 12:07:27 +0300 Subject: [PATCH 15/21] support closure as tile arg to get texpos --- library/LuaApi.cpp | 22 +++++++++++++++- library/lua/gui.lua | 43 ++++++++++++++++++++++--------- plugins/lua/buildingplan/pens.lua | 18 ++++++------- 3 files changed, 61 insertions(+), 22 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 174bedb56..29d343c17 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -161,6 +161,26 @@ static bool get_int_field(lua_State *L, T *pf, int idx, const char *name, int de return !nil; } +template +static bool get_int_or_closure_field(lua_State *L, T *pf, int idx, const char *name, int defval) +{ + lua_getfield(L, idx, name); + bool nil = lua_isnil(L, -1); + if (nil) { + *pf = T(defval); + } else if (lua_isnumber(L, -1)) { + *pf = T(lua_tointeger(L, -1)); + } else if (lua_isfunction(L, -1)) { + lua_call(L, 0, 1); + *pf = T(lua_tointeger(L, -1)); + lua_pop(L, 1); + } else { + luaL_error(L, "Field %s is not a number or closure function.", name); + } + lua_pop(L, 1); + return !nil; +} + static bool get_char_field(lua_State *L, char *pf, int idx, const char *name, char defval) { lua_getfield(L, idx, name); @@ -207,7 +227,7 @@ static void decode_pen(lua_State *L, Pen &pen, int idx) else pen.bold = lua_toboolean(L, -1); lua_pop(L, 1); - get_int_field(L, &pen.tile, idx, "tile", 0); + get_int_or_closure_field(L, &pen.tile, idx, "tile", 0); bool tcolor = get_int_field(L, &pen.tile_fg, idx, "tile_fg", 7); tcolor = get_int_field(L, &pen.tile_bg, idx, "tile_bg", 0) || tcolor; diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 0176c998e..8c61da6fd 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -912,6 +912,11 @@ local BASE_FRAME = { paused_pen = to_pen{fg=COLOR_RED, bg=COLOR_BLACK}, } +-- DFHack textures +-------------------------- + +-- Preloaded DFHack Asset +-- Use this handles if you need to get dfhack standard textures local texpos_handles = { green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12), @@ -925,6 +930,22 @@ local texpos_handles = { border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), } +-- Mathods to obtain valid texposes by handles +function tp_green_pin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.green_pin[offset]) +end +function tp_red_pin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.red_pin[offset]) +end +function tp_icons(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.icons[offset]) +end +function tp_on_off(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.on_off[offset]) +end +function tp_control_panel(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.control_panel[offset]) +end function tp_border_thin(offset) return dfhack.textures.getTexposByHandle(texpos_handles.border_thin[offset]) end @@ -940,27 +961,25 @@ end function tp_border_window(offset) return dfhack.textures.getTexposByHandle(texpos_handles.border_window[offset]) end -function tp_control_panel(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.control_panel[offset]) -end + local function make_frame(tp, double_line) local frame = copyall(BASE_FRAME) - frame.t_frame_pen = to_pen{ tile=tp(2), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.l_frame_pen = to_pen{ tile=tp(8), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.b_frame_pen = to_pen{ tile=tp(16), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.r_frame_pen = to_pen{ tile=tp(10), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.lt_frame_pen = to_pen{ tile=tp(1), ch=double_line and 201 or 218, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.lb_frame_pen = to_pen{ tile=tp(15), ch=double_line and 200 or 192, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.rt_frame_pen = to_pen{ tile=tp(3), ch=double_line and 187 or 191, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.rb_frame_pen = to_pen{ tile=tp(17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.t_frame_pen = to_pen{ tile=curry(tp, 2), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.l_frame_pen = to_pen{ tile=curry(tp, 8), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.b_frame_pen = to_pen{ tile=curry(tp, 16), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.r_frame_pen = to_pen{ tile=curry(tp, 10), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.lt_frame_pen = to_pen{ tile=curry(tp, 1), ch=double_line and 201 or 218, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.lb_frame_pen = to_pen{ tile=curry(tp, 15), ch=double_line and 200 or 192, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rt_frame_pen = to_pen{ tile=curry(tp, 3), ch=double_line and 187 or 191, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rb_frame_pen = to_pen{ tile=curry(tp, 17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } return frame end function FRAME_WINDOW(resizable) local frame = make_frame(tp_border_window, true) if not resizable then - frame.rb_frame_pen = to_pen{ tile=tp_border_panel(17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rb_frame_pen = to_pen{ tile=curry(tp_border_panel, 17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } end return frame end diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index d50ee4c75..817070b76 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -15,17 +15,17 @@ function reload_pens() GOOD_TILE_PEN = to_pen{ch='o', fg=COLOR_GREEN, tile=dfhack.screen.findGraphicsTile('CURSORS', 1, 2)} BAD_TILE_PEN = to_pen{ch='X', fg=COLOR_RED, tile=dfhack.screen.findGraphicsTile('CURSORS', 3, 0)} - VERT_TOP_PEN = to_pen { tile = gui.tp_border_thin(11), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_MID_PEN = to_pen { tile = gui.tp_border_thin(5), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_BOT_PEN = to_pen { tile = gui.tp_border_thin(12), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_TOP_PEN = to_pen { tile = curry(gui.tp_border_thin, 11), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_MID_PEN = to_pen { tile = curry(gui.tp_border_thin, 5), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_BOT_PEN = to_pen { tile = curry(gui.tp_border_thin, 12), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_LEFT_PEN = to_pen { tile = gui.tp_border_medium(13), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_MID_PEN = to_pen { tile = gui.tp_border_medium(6), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_RIGHT_PEN = to_pen { tile = gui.tp_border_medium(14), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_LEFT_PEN = to_pen { tile = curry(gui.tp_border_medium, 13), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_MID_PEN = to_pen { tile = curry(gui.tp_border_medium, 6), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_RIGHT_PEN = to_pen { tile = curry(gui.tp_border_medium, 14), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } - BUTTON_START_PEN = to_pen { tile = gui.tp_control_panel(14), ch = '[', fg = COLOR_YELLOW } - BUTTON_END_PEN = to_pen { tile = gui.tp_control_panel(16), ch = ']', fg = COLOR_YELLOW } - SELECTED_ITEM_PEN = to_pen { tile = gui.tp_control_panel(10), ch = string.char(251), fg = COLOR_YELLOW } + BUTTON_START_PEN = to_pen { tile = curry(gui.tp_control_panel, 14), ch = '[', fg = COLOR_YELLOW } + BUTTON_END_PEN = to_pen { tile = curry(gui.tp_control_panel, 16), ch = ']', fg = COLOR_YELLOW } + SELECTED_ITEM_PEN = to_pen { tile = curry(gui.tp_control_panel, 10), ch = string.char(251), fg = COLOR_YELLOW } MINI_TEXT_PEN = to_pen{fg=COLOR_BLACK, bg=COLOR_GREY} MINI_TEXT_HPEN = to_pen{fg=COLOR_BLACK, bg=COLOR_WHITE} From 5cafffaaf6a0d73605bb3501bc7b9d4204d0870d Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 14 Aug 2023 13:04:38 +0300 Subject: [PATCH 16/21] typos --- library/lua/gui.lua | 58 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 8c61da6fd..d94c1373b 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -885,37 +885,10 @@ ZScreenModal.ATTRS{ pass_mouse_clicks = false, } --- Framed screen object --------------------------- - --- Plain grey-colored frame. --- deprecated -GREY_FRAME = { - frame_pen = to_pen{ ch = ' ', fg = COLOR_BLACK, bg = COLOR_GREY }, - title_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_WHITE }, - signature_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, -} - --- The boundary used by the pre-steam DF screens. --- deprecated -BOUNDARY_FRAME = { - frame_pen = to_pen{ ch = 0xDB, fg = COLOR_GREY, bg = COLOR_BLACK }, - title_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, - signature_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, -} - -local BASE_FRAME = { - frame_pen = to_pen{ ch=206, fg=COLOR_GREY, bg=COLOR_BLACK }, - title_pen = to_pen{ fg=COLOR_BLACK, bg=COLOR_GREY }, - inactive_title_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK }, - signature_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK }, - paused_pen = to_pen{fg=COLOR_RED, bg=COLOR_BLACK}, -} - -- DFHack textures -------------------------- --- Preloaded DFHack Asset +-- Preloaded DFHack Assets -- Use this handles if you need to get dfhack standard textures local texpos_handles = { green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), @@ -930,7 +903,7 @@ local texpos_handles = { border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), } --- Mathods to obtain valid texposes by handles +-- Methods to obtain valid texposes by handles function tp_green_pin(offset) return dfhack.textures.getTexposByHandle(texpos_handles.green_pin[offset]) end @@ -962,6 +935,33 @@ function tp_border_window(offset) return dfhack.textures.getTexposByHandle(texpos_handles.border_window[offset]) end +-- Framed screen object +-------------------------- + +-- Plain grey-colored frame. +-- deprecated +GREY_FRAME = { + frame_pen = to_pen{ ch = ' ', fg = COLOR_BLACK, bg = COLOR_GREY }, + title_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_WHITE }, + signature_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, +} + +-- The boundary used by the pre-steam DF screens. +-- deprecated +BOUNDARY_FRAME = { + frame_pen = to_pen{ ch = 0xDB, fg = COLOR_GREY, bg = COLOR_BLACK }, + title_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, + signature_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, +} + +local BASE_FRAME = { + frame_pen = to_pen{ ch=206, fg=COLOR_GREY, bg=COLOR_BLACK }, + title_pen = to_pen{ fg=COLOR_BLACK, bg=COLOR_GREY }, + inactive_title_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK }, + signature_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK }, + paused_pen = to_pen{fg=COLOR_RED, bg=COLOR_BLACK}, +} + local function make_frame(tp, double_line) local frame = copyall(BASE_FRAME) From 25038648c0356c6e052adc78f1eb623937adbac6 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Tue, 15 Aug 2023 21:11:06 +0300 Subject: [PATCH 17/21] remove unused variable --- library/LuaApi.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 29d343c17..56052bbd3 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1380,6 +1380,13 @@ static void OpenModule(lua_State *state, const char *mname, lua_pop(state, 1); } +static void OpenModule(lua_State *state, const char *mname, const luaL_Reg *reg2) +{ + luaL_getsubtable(state, lua_gettop(state), mname); + luaL_setfuncs(state, reg2, 0); + lua_pop(state, 1); +} + #define WRAPM(module, function) { #function, df::wrap_function(module::function,true) } #define WRAP(function) { #function, df::wrap_function(function,true) } #define WRAPN(name, function) { #name, df::wrap_function(function,true) } @@ -1751,10 +1758,6 @@ static int textures_getTexposByHandle(lua_State *state) return 1; } -static const LuaWrapper::FunctionReg dfhack_textures_module[] = { - { NULL, NULL } -}; - static const luaL_Reg dfhack_textures_funcs[] = { { "loadTileset", textures_loadTileset }, { "getTexposByHandle", textures_getTexposByHandle }, @@ -3727,7 +3730,7 @@ void OpenDFHackApi(lua_State *state) luaL_setfuncs(state, dfhack_funcs, 0); OpenModule(state, "gui", dfhack_gui_module, dfhack_gui_funcs); OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs); - OpenModule(state, "textures", dfhack_textures_module, dfhack_textures_funcs); + OpenModule(state, "textures", dfhack_textures_funcs); OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs); OpenModule(state, "military", dfhack_military_module); OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs); From bbbb8fbb9c99ef2f22af38bf57e64dd43acca6fc Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Tue, 15 Aug 2023 21:18:52 +0300 Subject: [PATCH 18/21] invalid texpos is nil now --- plugins/lua/hotkeys.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 728b8e9df..422306be0 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -75,7 +75,7 @@ function HotspotMenuWidget:onRenderBody(dc) return dfhack.textures.getTexposByHandle(textures[offset]) end - if tp(1) == -1 then + if tp(1) == nil then dscreen.paintString(COLOR_WHITE, x, y + 0, '!DF!') dscreen.paintString(COLOR_WHITE, x, y + 1, '!Ha!') dscreen.paintString(COLOR_WHITE, x, y + 2, '!ck!') From c1945f7b54f139a90a31a5227e695e82aa868df2 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Thu, 17 Aug 2023 06:32:26 +0300 Subject: [PATCH 19/21] fix build err in gcc --- library/include/modules/Textures.h | 2 +- library/modules/Textures.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 17cd6e2fc..fa1f743be 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -38,7 +38,7 @@ DFHACK_EXPORT std::vector loadTileset(const std::string& file, /** * Get texpos by handle. - * Always use this function, if you need to get valid texpos for your texure. + * Always use this function, if you need to get valid texpos for your texture. * Texpos can change on game textures reset, but handle will be the same. */ DFHACK_EXPORT long getTexposByHandle(TexposHandle handle); diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 729bf0cae..31575dca0 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -120,7 +120,7 @@ std::vector Textures::loadTileset(const std::string& file, int til } DFSDL_FreeSurface(surface); - DEBUG(textures).print("loaded %i textures from '%s'\n", handles.size(), file.c_str()); + DEBUG(textures).print("loaded %zd textures from '%s'\n", handles.size(), file.c_str()); return handles; } From 6c5163af9ed458cbc5d69ec2d24aea89960b4ef7 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 27 Aug 2023 22:28:03 +0300 Subject: [PATCH 20/21] adjust adopt region reset step --- library/modules/Textures.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 31575dca0..48bc71e3c 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -178,7 +178,7 @@ struct tracking_stage_adopt_region : df::viewscreen_adopt_regionst { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { this->m_cur_step = this->cur_step; - if (this->m_cur_step == 2) + if (this->m_cur_step == 1) reset_texpos(); } INTERPOSE_NEXT(logic)(); From 4fb6b09b30abec70b742eaf9bcd90addde0185b8 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 28 Aug 2023 06:58:30 +0300 Subject: [PATCH 21/21] move textures to separate lua module --- library/lua/gui.lua | 65 +++------------------ library/lua/gui/textures.lua | 93 +++++++++++++++++++++++++++++++ plugins/lua/buildingplan/pens.lua | 19 ++++--- 3 files changed, 111 insertions(+), 66 deletions(-) create mode 100644 library/lua/gui/textures.lua diff --git a/library/lua/gui.lua b/library/lua/gui.lua index d94c1373b..ac25381ca 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -2,6 +2,7 @@ local _ENV = mkmodule('gui') +local textures = require('gui.textures') local utils = require('utils') local dscreen = dfhack.screen @@ -885,56 +886,6 @@ ZScreenModal.ATTRS{ pass_mouse_clicks = false, } --- DFHack textures --------------------------- - --- Preloaded DFHack Assets --- Use this handles if you need to get dfhack standard textures -local texpos_handles = { - green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), - red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12), - icons = dfhack.textures.loadTileset('hack/data/art/icons.png', 8, 12), - on_off = dfhack.textures.loadTileset('hack/data/art/on-off.png', 8, 12), - control_panel = dfhack.textures.loadTileset('hack/data/art/control-panel.png', 8, 12), - border_thin = dfhack.textures.loadTileset('hack/data/art/border-thin.png', 8, 12), - border_medium = dfhack.textures.loadTileset('hack/data/art/border-medium.png', 8, 12), - border_bold = dfhack.textures.loadTileset('hack/data/art/border-bold.png', 8, 12), - border_panel = dfhack.textures.loadTileset('hack/data/art/border-panel.png', 8, 12), - border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), -} - --- Methods to obtain valid texposes by handles -function tp_green_pin(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.green_pin[offset]) -end -function tp_red_pin(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.red_pin[offset]) -end -function tp_icons(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.icons[offset]) -end -function tp_on_off(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.on_off[offset]) -end -function tp_control_panel(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.control_panel[offset]) -end -function tp_border_thin(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.border_thin[offset]) -end -function tp_border_medium(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.border_medium[offset]) -end -function tp_border_bold(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.border_bold[offset]) -end -function tp_border_panel(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.border_panel[offset]) -end -function tp_border_window(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.border_window[offset]) -end - -- Framed screen object -------------------------- @@ -977,28 +928,28 @@ local function make_frame(tp, double_line) end function FRAME_WINDOW(resizable) - local frame = make_frame(tp_border_window, true) + local frame = make_frame(textures.tp_border_window, true) if not resizable then - frame.rb_frame_pen = to_pen{ tile=curry(tp_border_panel, 17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rb_frame_pen = to_pen{ tile=curry(textures.tp_border_panel, 17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } end return frame end function FRAME_PANEL(resizable) - return make_frame(tp_border_panel, false) + return make_frame(textures.tp_border_panel, false) end function FRAME_MEDIUM(resizable) - return make_frame(tp_border_medium, false) + return make_frame(textures.tp_border_medium, false) end function FRAME_BOLD(resizable) - return make_frame(tp_border_bold, true) + return make_frame(textures.tp_border_bold, true) end function FRAME_INTERIOR(resizable) - local frame = make_frame(tp_border_thin, false) + local frame = make_frame(textures.tp_border_thin, false) frame.signature_pen = false return frame end function FRAME_INTERIOR_MEDIUM(resizable) - local frame = make_frame(tp_border_medium, false) + local frame = make_frame(textures.tp_border_medium, false) frame.signature_pen = false return frame end diff --git a/library/lua/gui/textures.lua b/library/lua/gui/textures.lua new file mode 100644 index 000000000..6557b6e02 --- /dev/null +++ b/library/lua/gui/textures.lua @@ -0,0 +1,93 @@ +-- DFHack textures + +local _ENV = mkmodule('gui.textures') + +---@alias TexposHandle integer + +-- Preloaded DFHack Assets. +-- Use this handles if you need to get dfhack standard textures. +---@type table +local texpos_handles = { + green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), + red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12), + icons = dfhack.textures.loadTileset('hack/data/art/icons.png', 8, 12), + on_off = dfhack.textures.loadTileset('hack/data/art/on-off.png', 8, 12), + control_panel = dfhack.textures.loadTileset('hack/data/art/control-panel.png', 8, 12), + border_thin = dfhack.textures.loadTileset('hack/data/art/border-thin.png', 8, 12), + border_medium = dfhack.textures.loadTileset('hack/data/art/border-medium.png', 8, 12), + border_bold = dfhack.textures.loadTileset('hack/data/art/border-bold.png', 8, 12), + border_panel = dfhack.textures.loadTileset('hack/data/art/border-panel.png', 8, 12), + border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), +} + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_green_pin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.green_pin[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_red_pin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.red_pin[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_icons(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.icons[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_on_off(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.on_off[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_control_panel(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.control_panel[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_border_thin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_thin[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_border_medium(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_medium[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return TexposHandle +function tp_border_bold(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_bold[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_border_panel(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_panel[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_border_window(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_window[offset]) +end + +return _ENV diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index 817070b76..2ab76da06 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -1,6 +1,7 @@ local _ENV = mkmodule('plugins.buildingplan.pens') local gui = require('gui') +local textures = require('gui.textures') GOOD_TILE_PEN, BAD_TILE_PEN = nil, nil VERT_TOP_PEN, VERT_MID_PEN, VERT_BOT_PEN = nil, nil, nil @@ -15,17 +16,17 @@ function reload_pens() GOOD_TILE_PEN = to_pen{ch='o', fg=COLOR_GREEN, tile=dfhack.screen.findGraphicsTile('CURSORS', 1, 2)} BAD_TILE_PEN = to_pen{ch='X', fg=COLOR_RED, tile=dfhack.screen.findGraphicsTile('CURSORS', 3, 0)} - VERT_TOP_PEN = to_pen { tile = curry(gui.tp_border_thin, 11), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_MID_PEN = to_pen { tile = curry(gui.tp_border_thin, 5), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_BOT_PEN = to_pen { tile = curry(gui.tp_border_thin, 12), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_TOP_PEN = to_pen { tile = curry(textures.tp_border_thin, 11), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_MID_PEN = to_pen { tile = curry(textures.tp_border_thin, 5), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_BOT_PEN = to_pen { tile = curry(textures.tp_border_thin, 12), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_LEFT_PEN = to_pen { tile = curry(gui.tp_border_medium, 13), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_MID_PEN = to_pen { tile = curry(gui.tp_border_medium, 6), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_RIGHT_PEN = to_pen { tile = curry(gui.tp_border_medium, 14), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_LEFT_PEN = to_pen { tile = curry(textures.tp_border_medium, 13), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_MID_PEN = to_pen { tile = curry(textures.tp_border_medium, 6), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_RIGHT_PEN = to_pen { tile = curry(textures.tp_border_medium, 14), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } - BUTTON_START_PEN = to_pen { tile = curry(gui.tp_control_panel, 14), ch = '[', fg = COLOR_YELLOW } - BUTTON_END_PEN = to_pen { tile = curry(gui.tp_control_panel, 16), ch = ']', fg = COLOR_YELLOW } - SELECTED_ITEM_PEN = to_pen { tile = curry(gui.tp_control_panel, 10), ch = string.char(251), fg = COLOR_YELLOW } + BUTTON_START_PEN = to_pen { tile = curry(textures.tp_control_panel, 14), ch = '[', fg = COLOR_YELLOW } + BUTTON_END_PEN = to_pen { tile = curry(textures.tp_control_panel, 16), ch = ']', fg = COLOR_YELLOW } + SELECTED_ITEM_PEN = to_pen { tile = curry(textures.tp_control_panel, 10), ch = string.char(251), fg = COLOR_YELLOW } MINI_TEXT_PEN = to_pen{fg=COLOR_BLACK, bg=COLOR_GREY} MINI_TEXT_HPEN = to_pen{fg=COLOR_BLACK, bg=COLOR_WHITE}