PDA

View Full Version : DK2 texture format



Trass3r
September 30th, 2009, 19:17
First of all, here are all the EngineTextures.dat textures unpacked if you wanna investigate them:
http://ul.to/0ic5sm

Some older information can be obtained there:
http://durchschuss.du.funpic.de/index.php?cat=games&site=dk2textures
Those aren't up-to-date anymore though.


Format

There are 4 quality levels indicated by the file suffix ranging from MM0(highest) to MM3.

The file structure is as follows:

struct Header {
int resx; // width
int resy; // height
int size; // size of the rest of the file (i.e. without those 3 first ints)
int resxy; // ? containing the height and width in low and high word?
int uk; // = 0x75?
}

I just found files where that uk was 0xF5 instead of 0x75, maybe it's some flag field.


Compression

I thought the used compression could be S3TC (.dds compression) since it was introduced in DirectX 6, but I read it uses a fixed compression ratio so it's yet unlikely.

Trass3r
October 1st, 2009, 00:11
Ok I finally found the place where the textures get loaded:cool:
Setting a breakpoint didn't give me anything so far though :(

Regarding the use of high-res textures:
The texture sizes are checked to be in the range [16,128].
If they're not, another procedure is called that seems to check if the texturename contains the string "PRESCALED_TO" and in some cases again calls the procedure that called it to load the texture (didn't have a closer look at it).

fread_s(&resX, 4u, 1u, (int)dword_7920E0);
fread_s(&resY, 4u, 1u, (int)dword_7920E0);
v6 = 0;
if ( resX < 16 )
v6 = 1;
v7 = resY;
if ( resY < 16 )
v6 = 1;
if ( resX > 128 )
v6 = 1;
if ( resY > 128 )
v6 = 1;
if ( v6 )
{
sub_5911E0(v1);
}


int __fastcall sub_5911E0(int a1)
{
char *v1; // eax@1
char v2; // bl@1
int v3; // ebp@1
int i; // eax@4
int v5; // edi@4
int v6; // esi@4
int v7; // ebx@10
int result; // eax@11
int v9; // ebx@23
signed int j; // ebp@23
int v11; // edi@23
int v12; // esi@23
int v13; // edx@4
char v14; // zf@4
int v15; // ebx@6
int v16; // edx@6
char v17; // zf@6
int v18; // eax@8
int v19; // eax@9
int v20; // esi@9
char v21; // al@10
int v22; // ST18_4@17
int v23; // ST14_4@17
int v24; // ST10_4@17
int v25; // ST08_4@17
int v26; // ST04_4@17
int v27; // eax@17
int v28; // ST10_4@26
int v29; // ST08_4@26
int v30; // ST04_4@26
int v31; // eax@26
int v32; // eax@27
char v33; // cl@27
char v34; // [sp+414h] [bp-800h]@1
signed int v35; // [sp+10h] [bp-C04h]@10
char v36; // [sp+14h] [bp-C00h]@18

v3 = a1;
sprintf(&v34, *(const char **)(dword_792D44 + 12 * *(_DWORD *)(a1 + 36)));
v2 = 0;
v1 = strstr(&v34, "PRESCALED_TO");
if ( v1 )
{
*v1 = 0;
v2 = 1;
}
if ( v2 )
{
v6 = *(_DWORD *)(dword_792D44 + 12 * getMMxTextureOffset(&v34) + 4);
v13 = *(_DWORD *)(v6 + 60);
BYTE1(v13) |= 2u;
i = *(_DWORD *)v6;
v5 = v6 + 60;
v14 = *(_DWORD *)v6 == 0;
*(_DWORD *)(v6 + 60) = v13;
if ( v14 )
{
HandleMM0(v6);
for ( i = *(_DWORD *)v6; !*(_DWORD *)v6; i = *(_DWORD *)v6 )
{
v15 = *(_DWORD *)v5;
BYTE1(v15) &= 0xFDu;
*(_DWORD *)v5 = v15;
v6 = *(_DWORD *)(v6 + 24);
v16 = *(_DWORD *)(v6 + 60);
i = *(_DWORD *)v6;
v5 = v6 + 60;
BYTE1(v16) |= 2u;
v17 = *(_DWORD *)v6 == 0;
*(_DWORD *)(v6 + 60) = v16;
if ( !v17 )
break;
HandleMM0(v6);
}
}

mefistotelis
October 1st, 2009, 05:14
Nice work!

Trass3r
October 1st, 2009, 05:40
Thanks. I just can't seem to get it to break, neither memory bp nor hardware bps break.. or it simply crashes when done loading.
If I could just get DK2 to run in windowed mode or at least in 1600x1200x32 :(

Krizzie
October 1st, 2009, 05:45
Thanks. I just can't seem to get it to break, neither memory bp nor hardware bps break.. or it simply crashes when done loading.
If I could just get DK2 to run in windowed mode or at least in 1600x1200x32 :(

You can run the game in 1600x1200 by changing a registry value. But it isn't stable. And the view angle gets messed up so it doesn't play very well.

Trass3r
October 1st, 2009, 05:53
Immediately crashes for me.
Edit:
And my sound is gone when changing that. Anyways, my DK2 seems to be totally fucked up again, grainy pictures etc.

Metal Gear Rex
October 1st, 2009, 05:59
If you fix that, tell me. I have no idea how to fix that for me either. Though, I think it is only for the main menu but I'm not really sure as I don't remember.

mefistotelis
October 1st, 2009, 12:47
Thanks. I just can't seem to get it to break, neither memory bp nor hardware bps break..

You can find it with IDA, you only need to define everything ;)

look at this:

int __thiscall sub_591070(struct unkstruc6 *this, char *fname)
{
int idx; // eax@1
struct unkstruc6 *this1; // edi@1
int result; // eax@2
struct eheapitm1 *v5; // esi@3
int v6; // ebx@4
FILE *v7; // ST0C_4@3
int v8; // eax@3
int v9; // ecx@4
int v10; // eax@4
int vtable; // eax@8
void *v12; // eax@8
signed int DstBuf; // [sp+8h] [bp-18h]@3
signed int v14; // [sp+4h] [bp-1Ch]@3
struct eheapitm1 *v15; // [sp+10h] [bp-10h]@3
signed int v16; // [sp+1Ch] [bp-4h]@3
size_t ElementSize; // [sp+Ch] [bp-14h]@8

this1 = this;
idx = get_slot_for_texture_file(&this->field_434, fname);
if ( idx >= 0 )
{
fseek(this1->texturesFile, this1->field_434.field_410[idx].field_0, 0);
v7 = this1->texturesFile;
DstBuf = -1;
v14 = -1;
fname = (char *)-1;
read_from_file(&DstBuf, 4u, 1u, v7);
read_from_file(&v14, 4u, 1u, this1->texturesFile);
read_from_file(&fname, 4u, 1u, this1->texturesFile);
v8 = allocate_engine_heap(28);
v5 = (struct eheapitm1 *)v8;
v15 = (struct eheapitm1 *)v8;
v16 = 0;
if ( v8 )
{
v9 = v14;
v10 = DstBuf;
v6 = (int)fname;
v5->ptrfield_10 = (int)&unk_792D98;
v5->vtable = (int)&unkn_vtable1;
v5->field_4 = v10;
v5->field_8 = v9;
v5->field_C = v10 * dword_792DA0;
LOBYTE(v16) = 1;
v5->vtable = (int)&off_67039C;
v5->ptrfield_14 = 0;
if ( v6 )
v5->ptrfield_14 = allocate_engine_heap(v6);
v5->mem14_len = v6;
}
else
{
v5 = 0;
}
ElementSize = 0;
vtable = v5->vtable;
v16 = -1;
v12 = (void *)(*(int (__thiscall **)(_DWORD, _DWORD))(vtable + 32))(v5, &ElementSize);
read_from_file(v12, ElementSize, 1u, this1->texturesFile);
result = (int)v5;
}
else
{
result = 0;
}
return result;
}
As you see, it's easier to read if you'll define the function calling convention properly (most of them are __thiscall and they get "this" pointer in ecx).

Also, defining structures helps a lot, even if you can't properly name them.

struct unkstruc2
{
unsigned long ptrfield_0[9];
unsigned long field_24;
unsigned char field_28[16];
unsigned char field_38;
unsigned char field_39[3];
unsigned char field_3C;
unsigned char field_3D[3];
unsigned char field_40;
unsigned char field_41;
unsigned char field_42[970];
void *ptrfield_40C;
unkstruc2_sub2 field_410[2];
};

struct unkstruc6
{
unsigned long field_0;
void *field_4;
void *texturesFile;
unsigned char field_C[1060];
unsigned long field_430;
unkstruc2 field_434;
};

Trass3r
October 1st, 2009, 15:17
Unfortunately I'm not that of an IDA crack. Really need to get some tutorials to dive deeper into all that (defining structures,... there's even some way to write some kind of plugins for an exe afaik)
I already know that function, it does read in the texture but the question is where it is used (the bps were set on the read texture data from

read_from_file(v12, ElementSize, 1u, this1->texturesFile);

mefistotelis
October 1st, 2009, 19:37
Then we must learn where v12 is.

It's returned by function at (v5->vtable + 32) - to learn where it is, we need to look a bit higher:

v5->vtable = (int)&off_67039C;

So - to learn the address, we must analyze function pointed at (off_67039C + 32).

Trass3r
October 1st, 2009, 22:11
Well, most probably the textures are loaded at startup and used some time later when they're needed. That's why I didn't follow that code in IDA but debugged it.
So I put some breakpoints on the read texture data at v12 (which starts with that strange int resxy;) to break as soon as the game touches the data again.
But it doesn't. I think this should mean it isn't changed anymore and passed directly to DirectX, but S3TC uses fixed-rate compression and I don't know what was used before.

Maybe using a proxy dll like IKSLM did for DKER would shed some light on it, but I'm not really familiar with COM, DX & Co.

mefistotelis
October 1st, 2009, 23:46
I'm sure you can find it with these ways too...

Anyway, first try to take a look at:

int __thiscall sub_5907D0(struct eheapitm1 *this, int a1, int a2, int a3)
Especially its subfunctions.

btw, function (off_67039C + 32) was:

int __thiscall sub_5906C0(struct eheapitm1 *this, int *a2)
{
*a2 = this->mem14_len;
return this->ptrfield_14;
}
This is how I realized that the class with vtable at .rdata:0067039C must have a decoder in its methods.

Trass3r
October 2nd, 2009, 09:00
Hell yeah!:D
Just found a fantastic plugin that scans for vtables and look what it yielded:
http://img24.imageshack.us/img24/558/screeniedm.jpg

mefistotelis
October 2nd, 2009, 11:54
Wow.. you mean it was able to name all vtables?
How!?
I WANT IT!

EDIT:
I just tried to name them manually; I see the names, but I have no idea where's an offset for every name.

Trass3r
October 2nd, 2009, 17:52
It uses the C++ Runtime Type Information.
http://www.woodmann.com/collaborative/tools/index.php/Class_Informer

http://www.openrce.org/blog/view/1344/Class_Informer_IDA_plug-in

mefistotelis
October 3rd, 2009, 00:24
Thank you!

btw, I've got quite mature IDA project for DK1 (all routines named, most of structures defined). Let me know if you want it.

Oh, and don't forget to check the function which I posted before ;)

mefistotelis
October 4th, 2009, 19:56
class CEngineSurfaceBase {
public:
CEngineSurfaceBase(long w, long h);
virtual ~CEngineSurfaceBase();
virtual void fill(unsigned short val);
virtual bool put_image(struct CEngineSurfaceBase *dst, int pos_x, int pos_y);
virtual bool get_image(struct CEngineSurfaceBase *src, int pos_x, int pos_y);
virtual int func_10(void) = 0;
virtual bool out_supported(void) = 0;
virtual unsigned char *get_out_buffer(void)
virtual void func_1C(int a2);
virtual unsigned char *get_data_buffer(long *len);

long width;
long height;
unsigned long line_len;
void *ptrfield_10;
};


class CEngineCompressedSurface public CEngineSurfaceBase {
public:
CEngineCompressedSurface();
virtual ~CEngineCompressedSurface();
virtual bool put_image(struct CEngineSurfaceBase *dst, int pos_x, int pos_y);
virtual bool get_image(struct CEngineSurfaceBase *src, int pos_x, int pos_y);
virtual int func_10(void);
virtual bool out_supported(void);
virtual unsigned char *get_data_buffer(long *len);

unsigned char *data;
long data_len;
};

Did you made any progress?

Trass3r
October 5th, 2009, 21:17
So, have you already found the decompression function?

mefistotelis
October 5th, 2009, 22:57
So, have you already found the decompression function?

yes.
It's complex.

I've reworked a lot of code around it, but didn't touched it - it's scary. Floating point arithmetic. Very scary.


bool CEngineCompressedSurface::put_image(struct CEngineSurfaceBase *dst, int pos_x, int pos_y)
{
unsigned char *obuf;
unsigned char *ptr;
class GraphicsParams *gr_par;

if ( !dst->out_supported() )
return false;
obuf = dst->get_out_buffer();
gr_par = dst->graph_params;
ptr = obuf + dst->line_len * pos_y + pos_x * gr_par->bytes_per_pix;
sub_5B2450(gr_par->mask_g1, gr_par->mask_b1, gr_par->mask_a1, gr_par->mask_r1);
sub_5B26F0(this->data, ptr, dst->line_len, this->width, this->height);
dst->func_1C(obuf);
return true;
}
First one seems to make some arrays; 2nd one in the decoder.

I will upload the whole project when I have more time. It has all classes/structures defined, only decoder (and encoder - I found it too) is missing.

Trass3r
October 5th, 2009, 23:15
Yeah baby ;)
We could try to write a wrapper around the exe if the en-/decoder is that heavy.

mefistotelis
October 6th, 2009, 20:22
Yeah baby ;)
We could try to write a wrapper around the exe if the en-/decoder is that heavy.

Yeah, I'm thinking about it too.

But it's harder than KeeperFX.

It would be hard to re-create relocation table - new compilers have it stripped.
In DK1, relocation table wasn't stripped, so it was lot easier to wrap it.

Trass3r
October 6th, 2009, 21:24
There should be no need to if you ensure the exe can be loaded at its preferred imagebase by using a different imagebase for the loader.

mefistotelis
October 7th, 2009, 00:06
You're right; this could work.

Here's my complete project:
http://rapidshare.com/files/289605074/dk2_txtrtool01.zip

Trass3r
October 7th, 2009, 00:29
Yeah. Except another module comes in the way, then one might need to rebase that one.
http://sandsprite.com/CodeStuff/Using_an_exe_as_a_dll.html

How do you treat the missing exports table problem?
Did you reconstruct it for FX or use hardcoded offsets?

Edit: Never mind, just found your tutorial about KeeperFX ;)

mefistotelis
October 7th, 2009, 17:24
just found your tutorial about KeeperFX ;)

Nice.

The program that rebuilds export table is here, at bottom of the page:
http://keeper.lubie.org/html/dk_keeperfx.php

I'm thinking about a tool that could automate more of the exe-2-dll conversion; but I'm quite busy recently... we'll see.

Trass3r
October 9th, 2009, 03:12
Yeah already seen that, pretty cool.
Don't have much time either, gotta code for my bachelor's thesis.

EDIT:
Small sidenote, just found an interesting plugin that enables collaborative work on a binary, maybe it's helpful for you sometime ;)
http://www.idabook.com/collabreate/index.html

EDIT2:

btw, I've got quite mature IDA project for DK1 (all routines named, most of structures defined). Let me know if you want it.
You mean an IDA database? Could I see it?

mefistotelis
October 9th, 2009, 17:15
Ok, will upload it soon.

EDIT:
It's now here:
http://keeper.lubie.org/html/dk_keeperfx_devel.php

mefistotelis
October 31st, 2009, 13:13
In hex-rays 1.1, there's a support for floating point numbers. This would be very helpful in reverse-engineering the code.

Trass3r
November 1st, 2009, 21:37
Hey it's only 2000$ away ;)

Trass3r
August 11th, 2010, 20:10
In hex-rays 1.1, there's a support for floating point numbers. This would be very helpful in reverse-engineering the code.
1.1 is available now.


Here's my complete project:
http://rapidshare.com/files/289605074/dk2_txtrtool01.zip

Could you reupload it?
Also what DK2 exe did you use?

mefistotelis
August 18th, 2010, 21:58
The source is now here:
http://keeper.lubie.org/html/dk2_tools_other.php#txtrtool

If I recall correctly, I used EXE from v1.7.

JvetS
March 22nd, 2012, 22:20
Picking this up where you guys left off, as the sources for the dk2 texure tool don't seem to be close to completion or public use.
I'm currently reversing the function at 005B2450 (supposedly part of the decryption algorithm, from what I'm finding and from cross referencing the work done here).

I'm hoping I can get it working the other way around too, so people can swap out textures and recompile it.
If anyone has any info they'd like to share, or info they'd like to know, just ask. :)

EDIT:
Moving on to that second function, truly is a mess to reverse the stuff in there!
I'll keep you posted.

EDIT:
I've got breakpoints working over a remote connection, seems to be doing ok, sometimes the keyboard/mouse input becomes unresponsive, but otherwise it's working great.
Also, the application is sending these messages to one of the standard streams:

(R,G,B) = (5,6,5)
(R,G,B) (shifts) = (11,5,0)

The first message might indicate how many bits per color are being used.
The second message might indicate the shift lengths made during compression.

Still wondering what the random bytes are for...

EDIT:
bool scaryDecrypt(addr sourceBuffer, addr destinationBuffer, num rowByteLength, num textureWidth, num textureHeight);

Getting somewhere, being able to debug it remotely has been a huge help.

EDIT:
scaryDecrypt checks whether we are running in 16 or 32 bit display mode, the algorithms after that check are almost identical with some optimization/limitation for the selected mode.

Trass3r
May 3rd, 2012, 18:26
Looks good so far :)

JvetS
May 24th, 2012, 19:10
Hmmm... Haven't had the time to look at reversing the algorithm, as it's a pretty long operation seperated by some case specific instructions.
It might be easier to just dump the output values if you're only interested in unpacking instead of repacking the format.
Summer's coming up, than I'll have time to try out a few of the strategies I've come up with. (a function based on input output comparison, output dumping or full reversion of the original)

Trass3r
May 24th, 2012, 19:18
You could try the hex rays decompiler.

radu124
May 24th, 2012, 21:31
Hi,

I'm also interested.
I might also be able to help, though I don't have much time on my hands these days.
I tried IDA free, but the RTTI plugin did not work for me (crashed).
I'd like to have a look at the decompression algorithm, I have some experience with that.

Radu

Trass3r
May 24th, 2012, 21:48
There are some scripts as well: http://www.openrce.org/downloads/details/196

radu124
May 25th, 2012, 19:16
Thanks... already much easier,
Any other handy tools or from now on it's only the bare asm?
I'm somewhat puzzled, I've seen some nice C code earlier in the thread, is that extracted by hand?

Trass3r
May 25th, 2012, 19:19
The full version contains the HexRays decompiler.

radu124
May 25th, 2012, 20:40
Ah, that figures.
I tried RecStudio and Boomerang. Boomerang I couldn't get to work (in Wine it crashes and the linux bin is for an ancient release - I couldn't bring myself to boot windows).
From source no chance to build... RecStudio at least worked but addresses do not seem to match IDA.
RecStudio is not very powerful though...

werkt
August 20th, 2012, 17:17
I have successfully extracted a least-resistance path through the texture format, and with a couple of math tweaks, it should be feature complete for extraction soon. I'm drawing up a description of the format and will post back within a couple of days.

Trass3r
August 20th, 2012, 18:47
Can't wait for the details :)

Displacer
September 8th, 2012, 15:44
Taking a look at this. The first 8 bytes of the loaded texture data are a header of sorts.
The byte labeled here as a compression ID is actually data of some sort. Still tracing through it but it looks like that byte contains 3 pieces of info, isolated through shifts and logic operations.

Trass3r
September 25th, 2012, 19:17
Any news on this?

werkt
September 26th, 2012, 18:42
Admittedly I've been terrible about updates here.

I have the full set of textures extracted from my content, but there would be obvious copyright implications with posting them. I'm working on a full description of the decipher/decompress mechanism now - easily the most unportable and hard to describe sections are where the decipher uses fpu operations on decompressed data, and the jump/control word tables and float constants themselves may have their own copyright problems.

Trass3r
September 26th, 2012, 20:58
Just post some code with comments ;)

Trass3r
October 16th, 2012, 16:12
So?

werkt
October 19th, 2012, 19:35
Was on honeymoon, hope this has been worth waiting for :)

1092

Trass3r
October 19th, 2012, 19:54
Congrats :)

Edit: Crazy shit, that code.

Solra Bizna
October 26th, 2012, 22:41
I successfully incorporated that code into a program. With the right magic values, it (apparently) works. Now we just need to get it into a form humans can understand. :|

Trass3r
October 27th, 2012, 13:49
Yep, though I don't know if werkt has already worked on making the code clearer.

Solra Bizna
October 27th, 2012, 21:23
Further experimentation reveals that, while DK2 will preferentially load textures from the texture cache, if (and ONLY if) an entry for any of the mipmaps of, say, Bar_Table is not present in the texture cache, it will attempt to load Data\EngineTextures\Bar_Table.png instead. I'm writing a small program to disable texture cache entries that have counterparts on disk; this should make life easier for texture pack creators.

Edit: I finished the program, and did further testing... unfortunately, this method cannot be used to add higher-resolution textures; attempting to substitute a higher-resolution texture results in a crash.

1096

Feel free to mirror it, bundle it, whatever. You will have to run it once every time you add or remove a "patch" texture. I can also polish and release the program I used to extract the original textures... I'm afraid that without higher-resolution texture support, there's not a real reason to do more than that. There is still a non-zero possibility that one can add higher-resolution textures by editing the texture cache directly.

P.S. I did try using the undocumented(?) -highrestextures flag, to no avail.

Trass3r
October 28th, 2012, 14:51
I think the code actually checks the texture size, so it needs to be modified as well.

werkt
December 4th, 2012, 01:47
I can say with confidence that you won't be able to just bump up the texture size - there are a number of functions that validate images and provide buffers in the 16-128 texels per dimension range. The mipmap system is actually built around this: the mipmaps are each a power of 2 reduction in texels, with the max of 128 always at MM0, 64 at MM1, 32 at MM2, and 16 at MM3. There are some indications that the mipmap material structure has a 3 bit storage for the mipmaps (up to a max of MM7), so if you just manage to find all of the 0x80 references and patch them, the engine may be able to load 2048 x 2048 8 level mipmapped textures from EngineTextures.dat, though I've not managed to find how the engine handles non-DK2TextureCache mipmaps, i.e. the png load.

Sphax
August 5th, 2013, 09:50
Sorry to revive this old thread but I would love to contribute making HD textures for DK2 but I don't know if you have finally successfuly get a way to do this...

Trass3r
October 13th, 2013, 00:18
It's unlikely that this ever happens as it requires a lot of work.
And even if, you would still have the crappy models that are a lot harder and use vertex animations.

Trass3r
February 24th, 2014, 20:26
Yeah has anyone progressed on this?

Trass3r
March 6th, 2014, 20:26
I looked at the code and cleaned it up a bit but not really much.

Oleg Kramarenko
April 22nd, 2014, 08:05
Good afternoon. share program to unzip the file with textures.

I would appreciate.

tonihele
September 8th, 2014, 06:42
@Trass3r or anyone, can you share the cleaned up code please? Werkt has shared some code, but requires some hacking of the EXE file that I rather not do. It would really help our project https://github.com/tonihele/OpenDungeonKeeper. The reversal is otherwise progressing quite well, thanks to you guys.

Also on the side note if you have any information about the other formats. What we still have to figure out are the camera KCS files. We can read them, but we don't exactly understand them. Simple enough to try to get to work when we have proper 3D scenes maybe...

tonihele
September 9th, 2014, 20:29
They will look a lot better with the textures :) :

http://youtu.be/xaf4mNnWUcQ

werkt
September 10th, 2014, 16:59
Textures be damned, where's your implementation of ANIM! :


http://youtu.be/BvkwivaUpU8

tonihele
September 10th, 2014, 18:12
JMonkeyEngine doesn't support vertex animations :/ Need to code it in. Nice work werkt! What engine etc. are you using? And quit hogging the texture extraction code :)

werkt
September 10th, 2014, 19:34
That is just blender using my import operator.

tonihele
September 10th, 2014, 21:36
Nicely done. And your document was excellent. I have very little understanding myself on those, but I managed to come so far with your material.

tonihele
October 3rd, 2014, 06:47
Animations are done now. Well, not perfect, I don't exactly know why. Done enough to move forward :)

Struggling with the textures right now. I managed to extract data as you instructed with IDA. Not sure about the arrays though, not the easiest thing I've ever done. And one array address in your code was 4 bytes off from what I was able to extract. I was wondering about the STRIDE parameter. I tried to look from the FFMPEG source code as well. Is it just the size of the texture array (frame)? Or is it the unknown bit or what? (https://github.com/tonihele/OpenDungeonKeeper/blob/master/src/toniarts/opendungeonkeeper/tools/convert/enginetextures/EngineTexturesFile.java)


https://www.youtube.com/watch?v=D-R43gW9AGE

Trass3r
October 11th, 2015, 21:41
We could try to write a wrapper around the exe if the en-/decoder is that heavy.

Yeah, I'm thinking about it too.
But it's harder than KeeperFX.
It would be hard to re-create relocation table - new compilers have it stripped.
In DK1, relocation table wasn't stripped, so it was lot easier to wrap it.

There should be no need to if you ensure the exe can be loaded at its preferred imagebase by using a different imagebase for the loader.

I picked up that idea.
Currently doing it the other way around by injecting a dll.
Have a proof-of-concept implementation with the superzoom hack working nicely.

Trass3r
December 11th, 2015, 22:51
https://github.com/Trass3r/hijacklib/blob/dk2tests/hijacklib.cpp#L26

itchydani3l
May 2nd, 2016, 05:01
Could Trass3r or werkt please post a properly compiled script to rip these textures.
I'd also be okay with a privately shared PM.

Trass3r
January 16th, 2020, 19:27
Use OpenKeeper.