mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
195 lines
4.4 KiB
C++
195 lines
4.4 KiB
C++
/*
|
|
* sfall
|
|
* Copyright (C) 2010 The sfall team
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <d3d9.h>
|
|
#include <d3dx9.h>
|
|
#include <stdio.h>
|
|
#include <unordered_map>
|
|
|
|
#include "..\main.h"
|
|
#include "..\FalloutEngine\Fallout2.h"
|
|
|
|
#include "TalkingHeads.h"
|
|
|
|
namespace sfall
|
|
{
|
|
|
|
void _stdcall SetHeadTex(IDirect3DTexture9* tex, int width, int height, int xoff, int yoff);
|
|
|
|
extern IDirect3DDevice9* d3d9Device;
|
|
static std::unordered_map<__int64, IDirect3DTexture9**> texMap;
|
|
typedef std::unordered_map<__int64, IDirect3DTexture9**> :: iterator tex_itr;
|
|
typedef std::unordered_map<__int64, IDirect3DTexture9**> :: const_iterator tex_citr;
|
|
static BYTE overridden=0;
|
|
|
|
#pragma pack(push, 1)
|
|
struct Frm {
|
|
DWORD version;
|
|
WORD fps;
|
|
WORD actionFrame;
|
|
WORD frames;
|
|
union {
|
|
WORD xshifts[6];
|
|
struct {
|
|
WORD xshift;
|
|
WORD magic;
|
|
union {
|
|
char path[8];
|
|
__int64 key;
|
|
};
|
|
};
|
|
};
|
|
union {
|
|
WORD yshifts[6];
|
|
struct {
|
|
WORD yshift;
|
|
BYTE loaded;
|
|
BYTE broken;
|
|
IDirect3DTexture9** textures;
|
|
BYTE bakedBackground;
|
|
BYTE showHighlights;
|
|
};
|
|
};
|
|
};
|
|
struct Frame {
|
|
WORD width;
|
|
WORD height;
|
|
DWORD size;
|
|
WORD xoffset;
|
|
WORD yoffset;
|
|
BYTE data[1];
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static Frame* FramePointer(const Frm* frm, int frameno) {
|
|
Frame* result;
|
|
__asm {
|
|
mov eax, frm;
|
|
mov edx, frameno;
|
|
xor ebx, ebx;
|
|
call FuncOffs::frame_ptr_;
|
|
mov result, eax;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void LoadFrm(Frm* frm) {
|
|
tex_citr itr = texMap.find(frm->key);
|
|
if (itr == texMap.end()) {
|
|
//Load textures
|
|
char buf[MAX_PATH];
|
|
IDirect3DTexture9** textures = new IDirect3DTexture9*[frm->frames];
|
|
for (int i = 0; i < frm->frames; i++) {
|
|
sprintf(buf, "%s\\art\\heads\\%s\\%d.png", fo::var::patches, frm->path, i);
|
|
if (FAILED(D3DXCreateTextureFromFileExA(d3d9Device, buf, 0, 0, 1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, 0, 0, &textures[i]))) {
|
|
for (int j = 0; j < i; j++) textures[j]->Release();
|
|
delete[] textures;
|
|
frm->broken = 1;
|
|
return;
|
|
}
|
|
}
|
|
frm->textures = textures;
|
|
texMap[frm->key] = textures;
|
|
} else {
|
|
//Use preloaded textures
|
|
frm->textures = itr->second;
|
|
}
|
|
//mask image
|
|
for (int i = 0; i < frm->frames; i++) {
|
|
Frame* frame = FramePointer(frm, i);
|
|
if (frm->bakedBackground) {
|
|
memset(frame->data, 0x30, frame->size);
|
|
} else {
|
|
for (DWORD j = 0; j < frame->size; j++) {
|
|
if (frame->data[j]) frame->data[j] = 0x30;
|
|
}
|
|
}
|
|
}
|
|
frm->loaded = 1;
|
|
}
|
|
|
|
static void _stdcall DrawFrmHookInternal(Frm* frm, int frameno) {
|
|
if (!frm) return;
|
|
if (frm->magic == 0xabcd && !frm->broken) {
|
|
if (!frm->loaded) LoadFrm(frm);
|
|
if (frm->broken) return;
|
|
Frame* frame = FramePointer(frm, frameno);
|
|
SetHeadTex(frm->textures[frameno], frame->width, frame->height, frame->xoffset + frm->xshift, frame->yoffset + frm->yshift);
|
|
overridden = !frm->showHighlights;
|
|
} else overridden = 0;
|
|
}
|
|
|
|
static const DWORD gdDisplayFrameRet = 0x44AD06;
|
|
static void __declspec(naked) DrawFrmHook() {
|
|
__asm {
|
|
push edx;
|
|
push eax;
|
|
push edx;
|
|
push eax;
|
|
call DrawFrmHookInternal;
|
|
pop eax;
|
|
pop edx;
|
|
sub esp, 0x38;
|
|
mov esi, eax;
|
|
jmp gdDisplayFrameRet;
|
|
}
|
|
}
|
|
|
|
static const DWORD EndSpeechHookRet=0x447299;
|
|
void __declspec(naked) EndSpeechHook() {
|
|
__asm {
|
|
push label;
|
|
push ebx;
|
|
push ecx;
|
|
push edx;
|
|
push edi;
|
|
push ebp;
|
|
jmp EndSpeechHookRet;
|
|
label:
|
|
xor eax, eax;
|
|
push eax;
|
|
push eax;
|
|
push eax;
|
|
push eax;
|
|
push eax;
|
|
call SetHeadTex;
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static void __declspec(naked) TransTalkHook() {
|
|
__asm {
|
|
cmp overridden, 0;
|
|
jne skip;
|
|
jmp FuncOffs::talk_to_translucent_trans_buf_to_buf_;
|
|
skip:
|
|
retn 0x18;
|
|
}
|
|
}
|
|
|
|
void TalkingHeads::init() {
|
|
if (GetConfigInt("Graphics", "Use32BitHeadGraphics", 0)) {
|
|
HookCall(0x44AFB4, &TransTalkHook);
|
|
HookCall(0x44B00B, &TransTalkHook);
|
|
MakeCall(0x44AD01, &DrawFrmHook, true);
|
|
MakeCall(0x447294, &EndSpeechHook, true);
|
|
}
|
|
}
|
|
|
|
}
|