Replace screenshot addon with screenshotQuality CVar
Remove the embedded Screenshot addon (TOC + Lua) and WeirdUtilsScreenshot() Lua function. Compression quality is now controlled entirely via a CVar (saved to config.wtf), read fresh on each screenshot. CVar 0 disables PNG and falls through to original TGA.
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
-- Screenshot addon (embedded in DLL, loaded from memory)
|
||||
|
||||
BINDING_HEADER_SCREENSHOT = "Screenshot"
|
||||
|
||||
SLASH_SCREENSHOT1 = "/ss"
|
||||
SLASH_SCREENSHOT2 = "/screenshot"
|
||||
SlashCmdList["SCREENSHOT"] = function(msg)
|
||||
msg = string.lower(msg or "")
|
||||
if msg == "" or msg == "status" then
|
||||
local on, level = WeirdUtilsScreenshot()
|
||||
DEFAULT_CHAT_FRAME:AddMessage("Screenshots: " .. (on and "|cff00ff00ON|r" or "|cffff0000OFF|r") .. " (quality " .. level .. ")")
|
||||
elseif msg == "on" or msg == "enable" then
|
||||
WeirdUtilsScreenshot("enable")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("Screenshots |cff00ff00enabled|r")
|
||||
elseif msg == "off" or msg == "disable" then
|
||||
WeirdUtilsScreenshot("disable")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("Screenshots |cffff0000disabled|r")
|
||||
elseif tonumber(msg) then
|
||||
local q = tonumber(msg)
|
||||
if q >= 0 and q <= 9 then
|
||||
WeirdUtilsScreenshot("quality", q)
|
||||
DEFAULT_CHAT_FRAME:AddMessage("Screenshot quality: " .. q)
|
||||
else
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000Quality must be 0-9|r")
|
||||
end
|
||||
else
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00Screenshot|r commands:")
|
||||
DEFAULT_CHAT_FRAME:AddMessage(" /ss - Show status")
|
||||
DEFAULT_CHAT_FRAME:AddMessage(" /ss on|off - Enable/disable PNG screenshots")
|
||||
DEFAULT_CHAT_FRAME:AddMessage(" /ss 0-9 - Set compression level (0=fast, 9=small)")
|
||||
end
|
||||
end
|
||||
@@ -1,7 +0,0 @@
|
||||
## Interface: 11200
|
||||
## Title: WeirdUtils_Screenshot
|
||||
## Notes: PNG screenshot capture with configurable compression
|
||||
## Version: 1.0
|
||||
|
||||
|
||||
Screenshot.lua
|
||||
@@ -53,9 +53,22 @@ const ERROR_ALREADY_EXISTS: u32 = 183;
|
||||
// State
|
||||
// =============================================================================
|
||||
|
||||
var enabled: bool = true;
|
||||
var compression_level: i32 = 6; // user-facing 0–9, kept for Lua interface
|
||||
const tc: std.builtin.CallingConvention = .{ .x86_thiscall = .{} };
|
||||
const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
|
||||
|
||||
// CVar for compression level persistence (0–9, default 6)
|
||||
const CVAR_NAME = "screenshotQuality";
|
||||
const CVAR_LOOKUP: usize = 0x0063DEC0;
|
||||
const RegisterCVarFn = *const fn ([*:0]const u8, u32, u32, [*:0]const u8, u32, u32, u32, u32) callconv(fc) u32;
|
||||
const registerCVar: RegisterCVarFn = @ptrFromInt(0x0063DB90);
|
||||
|
||||
fn readCVarQuality() i32 {
|
||||
const cvar_ptr = hook.fastcall(u32, CVAR_LOOKUP, @intFromPtr(@as([*:0]const u8, CVAR_NAME)), @as(u32, 0));
|
||||
if (cvar_ptr == 0) return 6;
|
||||
const val = hook.readMem(i32, cvar_ptr + 40);
|
||||
return std.math.clamp(val, 0, 9);
|
||||
}
|
||||
|
||||
const TgaWriteFn = fn (u32, u32) callconv(tc) i32;
|
||||
var tga_hook: hook.Detour(TgaWriteFn) = .{};
|
||||
var screenshot_dir: [260]u8 = undefined;
|
||||
@@ -141,7 +154,9 @@ fn callOriginal(self: u32, filename: u32) i32 {
|
||||
// =============================================================================
|
||||
|
||||
fn tgaWriteDetour(self: u32, filename: u32) callconv(tc) i32 {
|
||||
if (!enabled) return callOriginal(self, filename);
|
||||
// CVar 0 = disabled, fall through to original TGA write
|
||||
const quality = readCVarQuality();
|
||||
if (quality == 0) return callOriginal(self, filename);
|
||||
|
||||
// Validate TGA header fields
|
||||
const pixel_data = hook.readMem(u32, self + 0x04);
|
||||
@@ -170,7 +185,7 @@ fn tgaWriteDetour(self: u32, filename: u32) callconv(tc) i32 {
|
||||
while (!mutex.tryLock()) {}
|
||||
defer mutex.unlock();
|
||||
|
||||
if (!enqueue(.{ .buffer = buffer.ptr, .width = width, .height = height, .size = size, .level = png.mapLevel(compression_level) })) {
|
||||
if (!enqueue(.{ .buffer = buffer.ptr, .width = width, .height = height, .size = size, .level = png.mapLevel(quality) })) {
|
||||
std.heap.page_allocator.free(buffer);
|
||||
return callOriginal(self, filename);
|
||||
}
|
||||
@@ -278,70 +293,6 @@ fn writePng(path: [*:0]const u8, pixels: [*]const u8, width: u16, height: u16, l
|
||||
png.encode(handle, writeToFile, pixels, width, height, level);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Lua helper: push f64 onto Lua stack via __fastcall(L_ECX, f64_on_stack)
|
||||
// =============================================================================
|
||||
|
||||
fn luaPushNumber(L_ptr: usize, n: f64) void {
|
||||
// lua_pushnumber at 0x6F3810 is __fastcall(L, double)
|
||||
// double skips EDX, goes on stack (8 bytes). Callee cleans with ret 8.
|
||||
const raw: [2]u32 = @bitCast(n);
|
||||
asm volatile (
|
||||
\\push %[hi]
|
||||
\\push %[lo]
|
||||
\\call *%[func]
|
||||
:
|
||||
: [_] "{ecx}" (L_ptr),
|
||||
[lo] "r" (raw[0]),
|
||||
[hi] "r" (raw[1]),
|
||||
[func] "r" (@as(u32, 0x6F3810)),
|
||||
: .{ .eax = true, .ecx = true, .edx = true, .memory = true, .cc = true });
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Lua C function: WeirdUtilsScreenshot(...)
|
||||
// No args → returns enabled (bool), compression_level (number)
|
||||
// ("enable") → enable PNG screenshots
|
||||
// ("disable") → disable (fall through to original TGA)
|
||||
// ("quality", N) → set compression level 0–9 (kept for addon compat)
|
||||
// =============================================================================
|
||||
|
||||
pub fn screenshotCommand(L: *anyopaque) callconv(.c) u32 {
|
||||
const L_ptr = @intFromPtr(L);
|
||||
|
||||
// lua_gettop(L) - __fastcall(L_ECX), EDX unused
|
||||
const nargs = hook.fastcall(i32, 0x6F3070, L_ptr, @as(u32, 0));
|
||||
|
||||
if (nargs == 0) {
|
||||
// lua_pushboolean(L, enabled)
|
||||
hook.fastcall(void, 0x6F39F0, L_ptr, @as(i32, if (enabled) 1 else 0));
|
||||
// lua_pushnumber(L, compression_level)
|
||||
luaPushNumber(L_ptr, @floatFromInt(compression_level));
|
||||
return 2;
|
||||
}
|
||||
|
||||
// lua_tostring(L, 1) - __fastcall(L_ECX, index_EDX)
|
||||
const raw_str = hook.fastcall(usize, 0x6F3690, L_ptr, @as(i32, 1));
|
||||
if (raw_str != 0) {
|
||||
const str: [*:0]const u8 = @ptrFromInt(raw_str);
|
||||
const arg = std.mem.span(str);
|
||||
|
||||
if (std.mem.eql(u8, arg, "enable")) {
|
||||
enabled = true;
|
||||
} else if (std.mem.eql(u8, arg, "disable")) {
|
||||
enabled = false;
|
||||
} else if (std.mem.eql(u8, arg, "quality")) {
|
||||
if (nargs >= 2) {
|
||||
// lua_tonumber(L, 2) - __fastcall(L_ECX, index_EDX), returns f64 in ST(0)
|
||||
const level = hook.fastcall(f64, 0x6F3620, L_ptr, @as(i32, 2));
|
||||
compression_level = std.math.clamp(@as(i32, @intFromFloat(level)), 0, 9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Install / Remove
|
||||
// =============================================================================
|
||||
@@ -354,6 +305,9 @@ pub fn installHook() void {
|
||||
g_is_hook_owner = result.is_owner;
|
||||
if (!g_is_hook_owner) return;
|
||||
|
||||
// Register CVar for compression quality persistence (saved to config.wtf)
|
||||
_ = registerCVar(CVAR_NAME, 0, 0, "6", 0, 1, 0, 0);
|
||||
|
||||
// CTgaFile::Write at 0x5a4810
|
||||
// __thiscall(self, filename) ret 4
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user