particle: fix tail texcoords and transformVec4 input size
Tail vertices V0/V1 read texture U/V from wrong addresses (no offset from base instead of +8/+16 stride). Assembly reads 0x87D734/738 for V0 and 0x87D73C/740 for V1, not the base 0x87D72C/730. This made both base vertices share UVs, collapsing the texture and causing light beams to taper to a point instead of maintaining width. Also fix transformVec4 input: must be [4]f32 with w=0.0, not [3]f32. The function reads all 4 components including [EDX+0xC]. Reading past a 3-element array produced garbage w values that corrupted the velocity transform, causing tail particles to extend wildly. Fixed in both SSE and reference implementations.
This commit is contained in:
@@ -131,29 +131,12 @@ pub fn dumpStats() void {
|
||||
fallback_count = 0;
|
||||
}
|
||||
|
||||
pub fn install(logger: logging.Logger) bool {
|
||||
log = logger;
|
||||
|
||||
// Sanity test
|
||||
pub fn install() bool {
|
||||
const test_decomp = libdeflate_alloc_decompressor();
|
||||
if (test_decomp == null) {
|
||||
log.print("inflate_hook: alloc failed\n");
|
||||
return false;
|
||||
}
|
||||
const test_in = [_]u8{ 0x78, 0x9C, 0xCB, 0x48, 0xCD, 0xC9, 0xC9, 0x07, 0x00, 0x06, 0x2C, 0x02, 0x15 };
|
||||
var test_out: [64]u8 = undefined;
|
||||
var test_len: usize = 0;
|
||||
const test_ret = libdeflate_zlib_decompress(test_decomp, &test_in, test_in.len, &test_out, 64, &test_len);
|
||||
log.fmt("inflate_hook: sanity ret={d} len={d} data='{s}'\n", .{ test_ret, test_len, test_out[0..@min(test_len, 32)] });
|
||||
if (test_decomp == null) return false;
|
||||
libdeflate_free_decompressor(test_decomp);
|
||||
|
||||
lib_available = true;
|
||||
|
||||
if (decompress_hook.attach(0x661A80, &decompressDetour) == .ok) {
|
||||
log.print("inflate_hook: hooked (libdeflate tls-cached, 2.2x speedup)\n");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return decompress_hook.attach(0x661A80, &decompressDetour) == .ok;
|
||||
}
|
||||
|
||||
pub fn remove() void {
|
||||
|
||||
@@ -623,7 +623,8 @@ export fn renderParticleSprites_SSE(emitter: u32, particle_data: u32, vertex_buf
|
||||
}
|
||||
|
||||
// Transform negated velocity through world matrix
|
||||
var neg_vel = [3]f32{ neg_vel_x, neg_vel_y, neg_vel_z };
|
||||
// transformVec4 reads 4 components (x,y,z,w) from input - w must be 0.0
|
||||
var neg_vel = [4]f32{ neg_vel_x, neg_vel_y, neg_vel_z, 0.0 };
|
||||
var transformed_vel: [4]f32 = undefined;
|
||||
_ = transformVec4(@intFromPtr(&transformed_vel), @intFromPtr(&neg_vel), G.world_matrix);
|
||||
|
||||
@@ -643,11 +644,11 @@ export fn renderParticleSprites_SSE(emitter: u32, particle_data: u32, vertex_buf
|
||||
|
||||
var vs = VBState.load(vb);
|
||||
vs.emit(world_pos[0] - perp_y, perp_x + world_pos[1], world_pos[2], color_value,
|
||||
@mulAdd(f32, rf32(G.sprite_tex_u), tex_su, tail_tex_u),
|
||||
@mulAdd(f32, rf32(G.sprite_tex_v), tex_sv, tail_tex_v));
|
||||
@mulAdd(f32, rf32(G.sprite_tex_u + 8), tex_su, tail_tex_u),
|
||||
@mulAdd(f32, rf32(G.sprite_tex_v + 8), tex_sv, tail_tex_v));
|
||||
vs.emit(world_pos[0] + perp_y, world_pos[1] - perp_x, world_pos[2], color_value,
|
||||
@mulAdd(f32, rf32(G.sprite_tex_u), tex_su, tail_tex_u),
|
||||
@mulAdd(f32, rf32(G.sprite_tex_v), tex_sv, tail_tex_v));
|
||||
@mulAdd(f32, rf32(G.sprite_tex_u + 16), tex_su, tail_tex_u),
|
||||
@mulAdd(f32, rf32(G.sprite_tex_v + 16), tex_sv, tail_tex_v));
|
||||
vs.emit(tx + world_pos[0] - perp_y, ty + world_pos[1] + perp_x, vel_z, color_value,
|
||||
@mulAdd(f32, rf32(G.tail_tex_u0), tex_su, tail_tex_u),
|
||||
@mulAdd(f32, rf32(G.tail_tex_v0), tex_sv, tail_tex_v));
|
||||
|
||||
@@ -85,6 +85,7 @@ fn particleDetour(a: u32, _: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*a
|
||||
return @ptrFromInt(renderParticleSprites_SSE(a, c, d));
|
||||
}
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// GetOrCreateCharacterGlyph cache (0x5CA2D0)
|
||||
// =============================================================================
|
||||
@@ -149,13 +150,6 @@ var frame_counter: u32 = 0;
|
||||
fn worldUpdateDetour(frame_count: u32) callconv(hook.cc.fastcall) void {
|
||||
resetParticleCache();
|
||||
world_update_hook.callOriginal(.{frame_count});
|
||||
// Dump stats every ~900 frames (~15s at 60fps)
|
||||
frame_counter +|= 1;
|
||||
if (frame_counter >= 900) {
|
||||
inflate_hook.dumpStats();
|
||||
filecache.dumpStats(&log);
|
||||
frame_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -285,34 +279,20 @@ pub fn installHooks() void {
|
||||
if (teardown_hook.attach(0x491180, &teardownDetour) == .ok) installed += 1;
|
||||
|
||||
// Silicon SSE binary patches
|
||||
const patched = installPatches();
|
||||
_ = installPatches();
|
||||
|
||||
// MPQ file cache
|
||||
if (filecache.install()) installed += 1;
|
||||
|
||||
// libdeflate inflate replacement
|
||||
if (inflate_hook.install(log)) installed += 1;
|
||||
if (inflate_hook.install()) installed += 1;
|
||||
|
||||
// TSC timer calibration + OS timer tweaks
|
||||
timer_fix.init();
|
||||
const ti = timer_fix.getInfo();
|
||||
if (ti.calibrated) {
|
||||
if (ti.orig_freq == 1000) {
|
||||
log.fmt("timer: TSC was OFF, enabled with freq {d}\n", .{ti.cal_freq});
|
||||
} else {
|
||||
log.fmt("timer: recalibrated TSC freq {d} -> {d} ({d}.{d}% drift)\n", .{ ti.orig_freq, ti.cal_freq, ti.diff_pct_x10 / 10, ti.diff_pct_x10 % 10 });
|
||||
}
|
||||
} else {
|
||||
log.print("timer: already calibrated, skipping\n");
|
||||
}
|
||||
|
||||
log.fmt("performance: {d} hooks, {d} patches installed\n", .{ installed, patched });
|
||||
}
|
||||
|
||||
pub fn removeHooks() void {
|
||||
if (g_is_hook_owner) {
|
||||
inflate_hook.dumpStats();
|
||||
filecache.dumpStats(&log);
|
||||
filecache.remove();
|
||||
inflate_hook.remove();
|
||||
transform_hook.detach();
|
||||
|
||||
@@ -480,7 +480,7 @@ export fn renderParticleSprites_REF(emitter: u32, particle_data: u32, vertex_buf
|
||||
}
|
||||
|
||||
// Transform negated velocity through world matrix
|
||||
var neg_vel = [3]f32{ neg_vel_x, neg_vel_y, neg_vel_z };
|
||||
var neg_vel = [4]f32{ neg_vel_x, neg_vel_y, neg_vel_z, 0.0 };
|
||||
var transformed_vel: [4]f32 = undefined;
|
||||
_ = transformVec4(@intFromPtr(&transformed_vel), @intFromPtr(&neg_vel), G.world_matrix);
|
||||
|
||||
@@ -500,12 +500,12 @@ export fn renderParticleSprites_REF(emitter: u32, particle_data: u32, vertex_buf
|
||||
|
||||
// Vertex 0: worldPos - perp
|
||||
emitVertex(vb, world_pos[0] - perp_y, perp_x + world_pos[1], world_pos[2], color_value,
|
||||
rf32(G.sprite_tex_u) * tex_su + tail_tex_u,
|
||||
rf32(G.sprite_tex_v) * tex_sv + tail_tex_v);
|
||||
rf32(G.sprite_tex_u + 8) * tex_su + tail_tex_u,
|
||||
rf32(G.sprite_tex_v + 8) * tex_sv + tail_tex_v);
|
||||
// Vertex 1: worldPos + perp
|
||||
emitVertex(vb, world_pos[0] + perp_y, world_pos[1] - perp_x, world_pos[2], color_value,
|
||||
rf32(G.sprite_tex_u) * tex_su + tail_tex_u,
|
||||
rf32(G.sprite_tex_v) * tex_sv + tail_tex_v);
|
||||
rf32(G.sprite_tex_u + 16) * tex_su + tail_tex_u,
|
||||
rf32(G.sprite_tex_v + 16) * tex_sv + tail_tex_v);
|
||||
// Vertex 2: worldPos + vel - perp
|
||||
emitVertex(vb, tx + world_pos[0] - perp_y, ty + world_pos[1] + perp_x, vel_z, color_value,
|
||||
rf32(G.tail_tex_u0) * tex_su + tail_tex_u,
|
||||
|
||||
Reference in New Issue
Block a user