Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions library/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2217,9 +2217,6 @@ void Core::onStateChange(color_ostream &out, state_change_event event)
}
}
break;
case SC_VIEWSCREEN_CHANGED:
Textures::init(out);
break;
default:
break;
}
Expand Down
69 changes: 54 additions & 15 deletions library/LuaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,26 @@ static bool get_int_field(lua_State *L, T *pf, int idx, const char *name, int de
return !nil;
}

template<class T>
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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1360,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) }
Expand Down Expand Up @@ -1709,19 +1736,31 @@ 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),
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 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 luaL_Reg dfhack_textures_funcs[] = {
{ "loadTileset", textures_loadTileset },
{ "getTexposByHandle", textures_getTexposByHandle },
{ NULL, NULL }
};

Expand Down Expand Up @@ -3691,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);
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);
Expand Down
75 changes: 30 additions & 45 deletions library/include/modules/Textures.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
#pragma once

#include "Export.h"
#include <string>
#include <vector>

#include "ColorText.h"
#include "Export.h"

struct SDL_Surface;

typedef uintptr_t TexposHandle;

namespace DFHack {

Expand All @@ -12,63 +19,41 @@ namespace DFHack {
*/
namespace Textures {

/**
* 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);

/**
* Call this when DFHack is being unloaded.
*
*/
void cleanup();
const uint32_t TILE_WIDTH_PX = 8;
const uint32_t TILE_HEIGHT_PX = 12;

/**
* 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.
* Load texture and get handle.
* Keep it to obtain valid texpos.
*/
DFHACK_EXPORT long getDfhackLogoTexposStart();
DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface);

/**
* Get the first texpos for the UI pin tiles. Each are 2x2 grids.
* Load tileset from image file.
* Return vector of handles to obtain valid texposes.
*/
DFHACK_EXPORT long getGreenPinTexposStart();
DFHACK_EXPORT long getRedPinTexposStart();
DFHACK_EXPORT std::vector<TexposHandle> loadTileset(const std::string& file,
int tile_px_w = TILE_WIDTH_PX,
int tile_px_h = TILE_HEIGHT_PX);

/**
* Get the first texpos for the DFHack icons. It's a 5x2 grid.
* Get texpos by handle.
* 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 getIconsTexposStart();
DFHACK_EXPORT long getTexposByHandle(TexposHandle handle);

/**
* Get the first texpos for the on and off icons. It's a 2x1 grid.
* Call this on DFHack init just once to setup interposed handlers and
* init static assets.
*/
DFHACK_EXPORT long getOnOffTexposStart();
void init(DFHack::color_ostream& out);

/**
* 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.
* Call this when DFHack is being unloaded.
*
*/
DFHACK_EXPORT long getThinBordersTexposStart();
DFHACK_EXPORT long getMediumBordersTexposStart();
DFHACK_EXPORT long getBoldBordersTexposStart();
DFHACK_EXPORT long getPanelBordersTexposStart();
DFHACK_EXPORT long getWindowBordersTexposStart();
void cleanup();

}
}
} // namespace Textures
} // namespace DFHack
70 changes: 41 additions & 29 deletions library/lua/gui.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

local _ENV = mkmodule('gui')

local textures = require('gui.textures')
local utils = require('utils')

local dscreen = dfhack.screen
Expand Down Expand Up @@ -912,33 +913,46 @@ local BASE_FRAME = {
paused_pen = to_pen{fg=COLOR_RED, bg=COLOR_BLACK},
}

local function make_frame(name, double_line)
local texpos = dfhack.textures['get'..name..'BordersTexposStart']()
local tp = function(offset)
if texpos == -1 then return nil end
return texpos + 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=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

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(textures.tp_border_window, true)
if not resizable then
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(textures.tp_border_panel, false)
end
function FRAME_MEDIUM(resizable)
return make_frame(textures.tp_border_medium, false)
end
function FRAME_BOLD(resizable)
return make_frame(textures.tp_border_bold, true)
end
function FRAME_INTERIOR(resizable)
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(textures.tp_border_medium, false)
frame.signature_pen = false
return frame
end

-- for compatibility with pre-steam code
GREY_LINE_FRAME = FRAME_PANEL
Expand All @@ -951,18 +965,16 @@ BOLD_FRAME = FRAME_BOLD
INTERIOR_FRAME = FRAME_INTERIOR
INTERIOR_MEDIUM_FRAME = FRAME_INTERIOR_MEDIUM


function paint_frame(dc,rect,style,title,inactive,pause_forced,resizable)
function paint_frame(dc, rect, style, title, inactive, pause_forced, resizable)
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)
Expand Down
Loading