Widescreen hack and some other fixes aka AiO Patch

Discuss Drakan: Order of the Flame with fellow players and post any technical problems here where an 'unofficial' support team will try and help you. Gameplay help questions can go here too.
User avatar
Mechanist
Dragon
Posts: 303
Joined: Wed Mar 07, 2018 7:27 pm
Location: Poland

Re: Widescreen hack and some other fixes aka AiO Patch

Post by Mechanist »

Ok, that's great :D

I've made good progress on letting the Editor import 32-bit textures (both without and with alpha); I hope to have a workable version ready by the end of the week.

Careful analysis showed that a lot less code needs to be changed than I initially expected.
Some parts of the existing import code are still poorly understood (especially the heap allocation part) - but those aren't really relevant to the problem at hand, and by now I've figured out enough of the important parts to be able to make this actually work.

UCyborg
Dragon
Posts: 433
Joined: Sun Jul 07, 2013 7:24 pm
Location: Slovenia

Re: Widescreen hack and some other fixes aka AiO Patch

Post by UCyborg »

Good to hear about your progress on the editor!

I fixed another odd bug today; should the DirectDraw surface creation fail when the textures are loading during level load, message will be output to the screen if debug messages are enabled. Previously, it just crashed because number of passed arguments after format string didn't match the number of format specifiers in format string.

So far, I've only seen that particular failure when running through WINE's default Direct3D implementation if the game's window doesn't have focus when the level is loading. Can easily happen in multiplayer (when server switches level). We were bitten by similar failure before; the famous difficulty selection crash could have been avoided if error checking was in place. Though in this case, it seems they just haven't tested the code that prints that specific error message.

There's just one small thing left on my mind ATM. Pressing "Stow weapon" key still does its thing when Rynn is performing other actions. So you can hide your weapon in the middle of the swing for example. At least in Surreal's The Suffering series, they have went for the approach of delaying the actions until Torque's animations are still playing. Delaying these things (if possible at all) would only be doable with some really good assembly black magic I guess, but blocking them is easier. Should I leave it as it is or change it so it's blocked during attack animation/being stunned?

If we leave it as it is, then we might as well allow quick weapon switches again, since it's consistent with mechanic of being able to use potions and such in these scenarios. Changing the mechanic with potions would definitely be a bad idea unless you'd make that change a part of optional mod aiming for more realism or something like that.

Thoughts?
"When a human being takes his life in depression, this is a natural death of spiritual causes. The modern barbarity of 'saving' the suicidal is based on a hair-raising misapprehension of the nature of existence." - Peter Wessel Zapffe

User avatar
Mechanist
Dragon
Posts: 303
Joined: Wed Mar 07, 2018 7:27 pm
Location: Poland

Re: Widescreen hack and some other fixes aka AiO Patch

Post by Mechanist »

UCyborg wrote: Should I leave it as it is or change it so it's blocked during attack animation/being stunned?
It doesn't really affect gameplay, right?
I mean, if I understand this correctly, there is no in-game advantage to stowing Rynn's weapon in the middle of an attack, since the animation continues regardless?

If that's the case, then feel free to do as you like there. Personally I think it should be blocked though, because changing/stowing weapons in the middle of a swing is just plain silly.
Then again, Rynn already keeps her weapons in some bizarre, transdimensional storage space, so whatever.

In case of the weapon switching, that had significant gameplay relevance, because the attack damage was calculated incorrectly when the weapon was changed in mid-swing.

UCyborg wrote: since it's consistent with mechanic of being able to use potions and such in these scenarios.
Actually, in multiplayer, the health pickups are usually "health crystals", not potions... IIRC, the conclusion we arrived at on Discord was that Rynn stabs herself with these crystals somehow :D
And there's no "potion drinking animation", even in singleplayer, so that's yet another sign that it was probably intended by the developers to work that way.

Plus, Rynn doesn't use a shield, so she has her left hand free when wielding a one-handed weapon :roll:

UCyborg
Dragon
Posts: 433
Joined: Sun Jul 07, 2013 7:24 pm
Location: Slovenia

Re: Widescreen hack and some other fixes aka AiO Patch

Post by UCyborg »

I mean, if I understand this correctly, there is no in-game advantage to stowing Rynn's weapon in the middle of an attack, since the animation continues regardless?

If that's the case, then feel free to do as you like there. Personally I think it should be blocked though, because changing/stowing weapons in the middle of a swing is just plain silly.

True, no gameplay relevance, just looks silly.

In case of the weapon switching, that had significant gameplay relevance, because the attack damage was calculated incorrectly when the weapon was changed in mid-swing.

I'm aware of that, I was just thinking of changing it back for cases when Rynn falls to the ground due to taking heavy damage in short amount of time. This wouldn't change the behavior mid-swing; would still be blocked.

You can reproduce it single player eg. if a bunch of Wartoks hit you at the same time. Should be even easier in MP with just 1 player attacking, just need a heavier weapons, I don't recall how much damage exactly it should have at least, probably around 40.
"When a human being takes his life in depression, this is a natural death of spiritual causes. The modern barbarity of 'saving' the suicidal is based on a hair-raising misapprehension of the nature of existence." - Peter Wessel Zapffe

User avatar
Mechanist
Dragon
Posts: 303
Joined: Wed Mar 07, 2018 7:27 pm
Location: Poland

Re: Widescreen hack and some other fixes aka AiO Patch

Post by Mechanist »

UCyborg wrote: Tue Aug 21, 2018 9:19 pm You can reproduce it single player eg. if a bunch of Wartoks hit you at the same time. Should be even easier in MP with just 1 player attacking, just need a heavier weapons, I don't recall how much damage exactly it should have at least, probably around 40.
Actually I don't think that knockdown (aka stun) effect is at all related to the amount of damage received.

Based on my earlier testing, as well as plenty of hands-on experience with knockdown-causing weapons (both in actual gameplay and in the Level Editor), I'm pretty confident that the knockdown is caused by "% chance of heavy hit" (or whatever the exact wording was) parameter in the Hand Weapon class properties.

UCyborg
Dragon
Posts: 433
Joined: Sun Jul 07, 2013 7:24 pm
Location: Slovenia

Re: Widescreen hack and some other fixes aka AiO Patch

Post by UCyborg »

Ah, OK. Explains why it feels a bit random.

I'll add that stow weapon blocking thing in the following days and revert the weapon switch block while being stunned.

Edit: Forgot to mention, when that error I mentioned happens during texture loads (DirectDraw surface creation failure), the affected texture will be missing. Still better than crashing.
"When a human being takes his life in depression, this is a natural death of spiritual causes. The modern barbarity of 'saving' the suicidal is based on a hair-raising misapprehension of the nature of existence." - Peter Wessel Zapffe

UCyborg
Dragon
Posts: 433
Joined: Sun Jul 07, 2013 7:24 pm
Location: Slovenia

Re: Widescreen hack and some other fixes aka AiO Patch

Post by UCyborg »

Done.
"When a human being takes his life in depression, this is a natural death of spiritual causes. The modern barbarity of 'saving' the suicidal is based on a hair-raising misapprehension of the nature of existence." - Peter Wessel Zapffe

User avatar
Mechanist
Dragon
Posts: 303
Joined: Wed Mar 07, 2018 7:27 pm
Location: Poland

Re: Widescreen hack and some other fixes aka AiO Patch

Post by Mechanist »

Nice :)

In the meantime, I hacked the Editor into accepting 32-bit textures.

Now importing 24-bit RGB .BMPs results in a 32-bit texture, not 16-bit.
When importing 32-bit ARGB .BMPs, it autodetects that it has a built-in alpha channel and sets up the metadata accordingly (so basically a 1-click import: no alpha conversion is needed) :D

32-bit XRGB .BMPs are functionally identical to 24-bit RGB, so the importer treats them the same as regular 24-bit .BMPs, and thus they don't generate an alpha channel.

The modified editor .exe is available on Discord; I'm not releasing it openly yet because it still lacks the badly needed alpha export functionality.

For future reference, here's the added code:

First, the changes to the .text section:

Disabled the check that causes 24-bit and 32-bit texture imports to be downconverted to 16-bit (this check applies when textures are auto-imported together with a .REO model):
0041B8C1 |> \8378 0C 10 |CMP DWORD PTR DS:[EAX+C],10
0041B8C5 |. EB 22 |JMP SHORT Level_Ed.0041B8E9
0041B8C7 |. 8B8C24 940000>|MOV ECX,DWORD PTR SS:[ESP+94]

After importing a bitmap, jumps to my code that checks it it's a 32-bit ARGB bitmap and calls function BMP_Reader again if appropriate (to deal with the alpha map .DEF stuff):
004233D4 |.- E9 CA9C0D00 JMP Level_Ed.004FD0A3
004233D9 |. 5F POP EDI
004233DA |. 5E POP ESI
004233DB |. 5D POP EBP
004233DC |. 5B POP EBX
004233DD |. 81C4 04010000 ADD ESP,104
004233E3 \. C2 1400 RETN 14

Redirection to my code that causes the correct amount of memory to be allocated when importing a 24-bit or 32-bit .BMP:
004234E1 |> \8B8424 F00A00>MOV EAX,DWORD PTR SS:[ESP+AF0]
004234E8 |.- E9 139B0D00 JMP Level_Ed.004FD000
004234ED | 90 NOP
004234EE |. 74 41 JE SHORT Level_Ed.00423531

Redirection to my code that takes over when dealing with 32-bit textures, skipping this 24-bit-only part:
00423606 |.- E9 279A0D00 JMP Level_Ed.004FD032
0042360B |. 8B46 04 MOV EAX,DWORD PTR DS:[ESI+4]
0042360E |. 33ED XOR EBP,EBP
00423610 |> 8B4424 24 /MOV EAX,DWORD PTR SS:[ESP+24]
00423614 |. 8B5424 18 |MOV EDX,DWORD PTR SS:[ESP+18]
00423618 |. 0FAFC5 |IMUL EAX,EBP
0042361B |. 8B0E |MOV ECX,DWORD PTR DS:[ESI]
0042361D |. 03C2 |ADD EAX,EDX
0042361F |. 33FF |XOR EDI,EDI
00423621 |. 3BCB |CMP ECX,EBX
00423623 |. 7E 14 |JLE SHORT Level_Ed.00423639
00423625 |> 8A50 02 |/MOV DL,BYTE PTR DS:[EAX+2]
00423628 |. 8A08 ||MOV CL,BYTE PTR DS:[EAX]
0042362A |. 8810 ||MOV BYTE PTR DS:[EAX],DL
0042362C |. 8848 02 ||MOV BYTE PTR DS:[EAX+2],CL
0042362F |. 83C0 03 ||ADD EAX,3
00423632 |. 8B0E ||MOV ECX,DWORD PTR DS:[ESI]
00423634 |. 47 ||INC EDI
00423635 |. 3BF9 ||CMP EDI,ECX
00423637 |.^ 7C EC |\JL SHORT Level_Ed.00423625
00423639 |> 8B46 04 |MOV EAX,DWORD PTR DS:[ESI+4]
0042363C |. 45 |INC EBP
0042363D |. 3BE8 |CMP EBP,EAX
0042363F |.^ 7C CF \JL SHORT Level_Ed.00423610
00423641 |> 8B6C24 10 MOV EBP,DWORD PTR SS:[ESP+10] ; The byte order has been flipped

Disabled the check that causes 24-bit and 32-bit texture imports to be downconverted to 16-bit (this check applies when textures are manually imported from the Databases window menu):
00426EC1 |. /E9 30080000 JMP Level_Ed.004276F6
00426EC6 |> |EB 14 JMP SHORT Level_Ed.00426EDC
00426EC8 | |90 NOP
00426EC9 | |90 NOP
00426ECA | |90 NOP
00426ECB | |90 NOP
00426ECC |. |8D85 0C060000 LEA EAX,DWORD PTR SS:[EBP+60C]

Now, the code added in the new code section:
004FD000 8BD0 MOV EDX,EAX ; 24-bit to 32-bit bitmap format conversion handler, part 1
004FD002 3BC3 CMP EAX,EBX ; It's OK to use EDX up there without saving it, since it gets overwritten upon returning anyway
004FD004 8B4424 24 MOV EAX,DWORD PTR SS:[ESP+24] ; Byte width of each of the bitmap's rows
004FD008 - 0F85 E264F2FF JNZ Level_Ed.004234F0 ; Bail out if the right conditions aren't met
004FD00E 85D2 TEST EDX,EDX
004FD010 8B5424 28 MOV EDX,DWORD PTR SS:[ESP+28] ; Bits per pixel
004FD014 75 16 JNZ SHORT Level_Ed.004FD02C ; Don't change anything if this an alpha map being loaded
004FD016 83FA 18 CMP EDX,18
004FD019 75 11 JNZ SHORT Level_Ed.004FD02C ; We only care about 24bpp bitmaps here
004FD01B 8B4C24 1C MOV ECX,DWORD PTR SS:[ESP+1C] ; Pixel width of each row; again, it's OK to use ECX without saving here
004FD01F 8BC1 MOV EAX,ECX
004FD021 C1E0 02 SHL EAX,2 ; Multiply the pixel width by 4 to get byte width for 32-bit texture
004FD024 83C2 08 ADD EDX,8 ; Override the texture type to 32 bits per pixel
004FD027 - E9 0D65F2FF JMP Level_Ed.00423539
004FD02C - E9 0465F2FF JMP Level_Ed.00423535
004FD031 90 NOP
004FD032 837C24 28 18 CMP DWORD PTR SS:[ESP+28],18 ; This part converts the 24-bit bitmap RGB format to 32-bit ARGB format
004FD037 75 3E JNZ SHORT Level_Ed.004FD077 ; Is this a 24-bit BMP? Skip if it isn't
004FD039 83BC24 F00A0000>CMP DWORD PTR SS:[ESP+AF0],1 ; 1 if loading an alpha map; 0 otherwise.
004FD041 74 5A JE SHORT Level_Ed.004FD09D ; Skip the conversion entirely if we're loading an alpha map
004FD043 8B6C24 18 MOV EBP,DWORD PTR SS:[ESP+18] ; Pointer to beginning of pixel byte data
004FD047 8B4424 1C MOV EAX,DWORD PTR SS:[ESP+1C] ; Horizontal width of bitmap (px)
004FD04B 8B5424 20 MOV EDX,DWORD PTR SS:[ESP+20] ; Vertical height of bitmap (px)
004FD04F 0FAFD0 IMUL EDX,EAX ; Number of pixels in the imported bitmap
004FD052 6BCA 03 IMUL ECX,EDX,3 ; Number of bytes in the imported bitmap
004FD055 83E9 03 SUB ECX,3 ; Start of the conversion loop
004FD058 4A DEC EDX
004FD059 66:8B4429 01 MOV AX,WORD PTR DS:[ECX+EBP+1]
004FD05E 66:3E:894495 02 MOV WORD PTR DS:[EBP+EDX*4+2],AX
004FD064 33C0 XOR EAX,EAX
004FD066 8A2429 MOV AH,BYTE PTR DS:[ECX+EBP]
004FD069 66:3E:894495 00 MOV WORD PTR DS:[EBP+EDX*4],AX
004FD06F 85D2 TEST EDX,EDX
004FD071 ^ 75 E2 JNZ SHORT Level_Ed.004FD055
004FD073 C646 0C 20 MOV BYTE PTR DS:[ESI+C],20 ; Overwrite the amount of bits per pixel to 32-bit
004FD077 8B6C24 18 MOV EBP,DWORD PTR SS:[ESP+18] ; At this point, the texture is guaranteed to be 32-bit in any case
004FD07B 8B4424 1C MOV EAX,DWORD PTR SS:[ESP+1C] ; Horizontal width of bitmap (px)
004FD07F 8B5424 20 MOV EDX,DWORD PTR SS:[ESP+20] ; Vertical height of bitmap (px)
004FD083 0FAFD0 IMUL EDX,EAX ; Number of pixels in the imported bitmap
004FD086 4A DEC EDX ; Start of the byte-shifting loop
004FD087 3E:8B4495 00 MOV EAX,DWORD PTR DS:[EBP+EDX*4] ; Grab the DWORD
004FD08C C1C8 08 ROR EAX,8 ; Adjust the byte placement
004FD08F 3E:894495 00 MOV DWORD PTR DS:[EBP+EDX*4],EAX ; Then put it back
004FD094 85D2 TEST EDX,EDX ; Are we done here?
004FD096 ^ 75 EE JNZ SHORT Level_Ed.004FD086
004FD098 - E9 A465F2FF JMP Level_Ed.00423641 ; Jump back to the Editor's code, skipping the 24-bit byte-fliping routine
004FD09D - E9 6965F2FF JMP Level_Ed.0042360B ; Jump back to the 24-bit byte-flipping routine
004FD0A2 90 NOP
004FD0A3 83BC24 28010000>CMP DWORD PTR SS:[ESP+128],1 ; 1 if this is an alpha map being added; 0 otherwise
004FD0AB 74 4D JE SHORT Level_Ed.004FD0FA ; Don't mess with the alpha map imports
004FD0AD 3E:837D 0C 20 CMP DWORD PTR DS:[EBP+C],20 ; Bits per pixel
004FD0B2 75 46 JNZ SHORT Level_Ed.004FD0FA ; Don't touch non-32-bit textures
004FD0B4 52 PUSH EDX
004FD0B5 3E:8B55 24 MOV EDX,DWORD PTR DS:[EBP+24] ; Handle to memory buffer containing texture pixel data
004FD0B9 52 PUSH EDX ; We need a 2nd copy for unlocking the memory later
004FD0BA 52 PUSH EDX
004FD0BB FF15 00614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalLock>; Convert the handle into a pointer
004FD0C1 85C0 TEST EAX,EAX ; Did it work?
004FD0C3 74 31 JE SHORT Level_Ed.004FD0F6 ; Bail out if it didn't
004FD0C5 3E:8B7D 00 MOV EDI,DWORD PTR DS:[EBP] ; Horizontal width of texture (px)
004FD0C9 3E:8B5D 04 MOV EBX,DWORD PTR DS:[EBP+4] ; Vertical height of texture (px)
004FD0CD 0FAFFB IMUL EDI,EBX ; Number of texture pixels
004FD0D0 8BDF MOV EBX,EDI
004FD0D2 4F DEC EDI ; Loop through all of the alpha bytes
004FD0D3 807CB8 03 00 CMP BYTE PTR DS:[EAX+EDI*4+3],0 ; Are there any nonzero ones?
004FD0D8 75 06 JNZ SHORT Level_Ed.004FD0E0
004FD0DA 85FF TEST EDI,EDI
004FD0DC ^ 75 F4 JNZ SHORT Level_Ed.004FD0D2
004FD0DE EB 0C JMP SHORT Level_Ed.004FD0EC
004FD0E0 4B DEC EBX ; Loop through all of the alpha bytes (again!)
004FD0E1 807C98 03 FF CMP BYTE PTR DS:[EAX+EBX*4+3],0FF ; Are there any non-0FFh ones?
004FD0E6 75 17 JNZ SHORT Level_Ed.004FD0FF
004FD0E8 85DB TEST EBX,EBX
004FD0EA ^ 75 F4 JNZ SHORT Level_Ed.004FD0E0
004FD0EC FF15 04614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalUnlock>; Unlock the memory buffer
004FD0F2 33C0 XOR EAX,EAX
004FD0F4 EB 03 JMP SHORT Level_Ed.004FD0F9
004FD0F6 F7D0 NOT EAX
004FD0F8 5A POP EDX
004FD0F9 5A POP EDX
004FD0FA - E9 DA62F2FF JMP Level_Ed.004233D9 ; Jump back to the Editor's original code
004FD0FF FF15 04614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalUnlock>; Unlock the memory buffer
004FD105 5A POP EDX
004FD106 8B9C24 20010000 MOV EBX,DWORD PTR SS:[ESP+120] ; Pointer to the start of palette data
004FD10D 8D7424 14 LEA ESI,DWORD PTR SS:[ESP+14] ; Pointer to the full path to the imported .BMP file
004FD111 8BBC24 18010000 MOV EDI,DWORD PTR SS:[ESP+118] ; Unknown; possibly some SEH-related stuff
004FD118 6A 01 PUSH 1
004FD11A 6A FF PUSH -1
004FD11C 53 PUSH EBX
004FD11D 56 PUSH ESI
004FD11E 57 PUSH EDI
004FD11F 8BCD MOV ECX,EBP ; Pointer to the start of the texture metadata in working memory
004FD121 E8 CA62F2FF CALL <Level_Ed.BMP_Reader> ; Call function BMP_Reader, in order to get the .DEF stuff set up correctly for the alpha map import
004FD126 3E:C645 10 08 MOV BYTE PTR DS:[EBP+10],8 ; Override the number of alpha bits to 8 (shouldn't actually be needed; just in case though)
004FD12B 3E:8A5D 31 MOV BL,BYTE PTR DS:[EBP+31] ; Texture.FLAGS
004FD12F 80E3 FE AND BL,0FE ; Clear FLAGS.0
004FD132 80CB 02 OR BL,2 ; Set FLAGS.1
004FD135 3E:885D 31 MOV BYTE PTR DS:[EBP+31],BL ; Put the updated value back
004FD139 ^ EB BF JMP SHORT Level_Ed.004FD0FA

UCyborg
Dragon
Posts: 433
Joined: Sun Jul 07, 2013 7:24 pm
Location: Slovenia

Re: Widescreen hack and some other fixes aka AiO Patch

Post by UCyborg »

Nicely done! I took another look at lens flares. On my Radeon R2 without dgVoodoo, when the game locks the z-buffer to read it, values in it are pretty strange compared to what usually appears through dgVoodoo or without on other cards. Because of that, lens flares are decided to be invisible. At least that's what I think it happens.

I also figured Dege's patch that adds 24-bit mask is a bit strange when you get a bit context. The loop above AND EBP,00FFFFFF instruction you see in my previous post constructs the mask from bitness of the z-buffer and stores it in EBP. So usually the depth of the entire z-buffer is 32-bit, which gives the mask 0xFFFFFFFF, but in most cases only 24 bits is used for depth component and the game might not be able to handle buffer that uses 32 bits for depth, even if it was available. We ensure that in callback function that's called by IDirect3D3::EnumZBufferFormats. Note that the original function doesn't take mask into account, so it never considers 32-bit buffer formats, only pure 24-bit ones.

The point is, instead of using bitness of the buffer to construct the mask, which was corrected at the end with AND instruction, we can pull the mask directly from the data we receive a after call to IDirectDrawSurface4::Lock. So besides removing some redundant code from the function in Dragon.rfl I mentioned previously and adjusting some offsets, I also modified function in Drakan.exe at 0x439FA0, more precisely instruction at 0x43A006 to take depth mask instead of buffer bitness. Just before the function returns, the value (mask) is written to a variable which pointer is passed to called function.

Updated version is up as always.
"When a human being takes his life in depression, this is a natural death of spiritual causes. The modern barbarity of 'saving' the suicidal is based on a hair-raising misapprehension of the nature of existence." - Peter Wessel Zapffe

User avatar
Mechanist
Dragon
Posts: 303
Joined: Wed Mar 07, 2018 7:27 pm
Location: Poland

Re: Widescreen hack and some other fixes aka AiO Patch

Post by Mechanist »

Ok, I tested that with 18.4.1 Radeon drivers (haven't updated them yet):
  • Without antialiasing: same as before - no lens flares, yes flashing screen corruption,
  • With forced AA: same as before - no lens flares, no screen corruption either,
  • With dgVoodoo: yes lens flares, no screen corruption
So whatever the problem is... it doesn't look like it was the z-buffer mask :(

UCyborg
Dragon
Posts: 433
Joined: Sun Jul 07, 2013 7:24 pm
Location: Slovenia

Re: Widescreen hack and some other fixes aka AiO Patch

Post by UCyborg »

I only shortened the code to get rid of redundant bits, so no functionality was altered. What actually goes wrong is this; at the API level, we're led to believe we're dealing with 24-bit (integer) depth buffer. But what actually happens on AMD cards, we get the full blown 32-bit (float) buffer.

This format might be more common today so my guess is it's used internally by default and nothing's in place for backward compatibility in the driver that would expose it in expected format. There's no way to control this from old Direct3D.

Checking the 8 most significant bits of the value in depth buffer to determine whether we're dealing with an 24-bit integer or 32-bit float and converting it in latter case is the idea I have. Should at least solve the problem of lens flares not showing.

I'll post back when I have some results.
"When a human being takes his life in depression, this is a natural death of spiritual causes. The modern barbarity of 'saving' the suicidal is based on a hair-raising misapprehension of the nature of existence." - Peter Wessel Zapffe

User avatar
Mechanist
Dragon
Posts: 303
Joined: Wed Mar 07, 2018 7:27 pm
Location: Poland

Re: Widescreen hack and some other fixes aka AiO Patch

Post by Mechanist »

UCyborg wrote: But what actually happens on AMD cards, we get the full blown 32-bit (float) buffer.

This format might be more common today so my guess is it's used internally by default and nothing's in place for backward compatibility
Wow, that sounds like a complete disaster! It's amazing that more things aren't broken then.

So would that be related to the flickering insane corruption that happens when the lightning flashes (even if off-screen) - presumably due to garbage data being written to the z-buffer (in the wrong format)?
Or is that another problem entirely?

In other news... I have some more fixes upcoming for the Level Editor in the next couple of days:
  • Squash long-standing bug where pixel color values are unexpectedly lower than they should be when exporting 16-bit textures from a database (thus corrupting the image data), <EDIT: Done!>
  • Make 16-bit textures with alpha channel exportable,
  • Make 32-bit textures exportable (regardless of presence/absence of alpha channel).

EDIT: Ok, I finally fixed the original 16-bit export code (for non-alpha-mapped textures); now it no longer distorts the colorspace mapping when exporting 16-bit textures.

The whole change fits in the .text section (in fact, my code is still 2 bytes shorter, despite performing a more complicated transform):
{Initial states of the relevant registers, for context:}
EAX = 0,
ECX = Vertical height of the source bitmap,
ESI = Pointer to the start of source texture metadata,
EDI = EBX = Pointer to the start of the target pixel data buffer,
ESP - Nothing special there; it's being used for its usual purpose in this case.

Note: Loading these 2 pointers at the very end is required, since these values are used by the subsequent code; not loading them causes an access violation, due to an attempt to read data from a nonexistent address.

00421C85 8B6C24 14 MOV EBP,DWORD PTR SS:[ESP+14] ; Pointer to start of the source texture pixel data
00421C89 0FAF0E IMUL ECX,DWORD PTR DS:[ESI] ; Vertical height of the source bitmap, times the horizontal width of the source bitmap
00421C8C 49 DEC ECX ; Start of the conversion loop
00421C8D 6BD1 03 IMUL EDX,ECX,3 ; Calculate the right offset for the target texture pixel data
00421C90 66:3E:8B444D >MOV AX,WORD PTR DS:[EBP+ECX*2] ; Load the 16-bit pixel data
00421C96 C1E0 03 SHL EAX,3 ; Adjust the blue bits to the right position
00421C99 8BD8 MOV EBX,EAX
00421C9B C1EB 05 SHR EBX,5 ; Shift the blue MSBs to where the missing blue LSBs need to be
00421C9E 80E3 07 AND BL,7 ; Zero out the irrelevant green bits
00421CA1 09C3 OR EBX,EAX ; The correct conversion result is now in BL
00421CA3 885C3A 02 MOV BYTE PTR DS:[EDX+EDI+2],BL ; Write the blue pixel data
00421CA7 C1E8 06 SHR EAX,6 ; Adjust the green bits to the right position
00421CAA 50 PUSH EAX ; Store a copy for safekeeping
00421CAB 24 FC AND AL,0FC ; Zero out the irrelevant blue bits
00421CAD 8BD8 MOV EBX,EAX
00421CAF C1EB 06 SHR EBX,6 ; Shift the green MSBs to where the missing green LSBs need to be
00421CB2 80E3 03 AND BL,3 ; Zero out the irrelevant red bits
00421CB5 09C3 OR EBX,EAX ; The correct conversion result is now in BL
00421CB7 58 POP EAX ; Restore the unmodified value
00421CB8 885C3A 01 MOV BYTE PTR DS:[EDX+EDI+1],BL ; Write the green pixel data
00421CBC C1E8 05 SHR EAX,5 ; Adjust the red bits to the right position
00421CBF 24 F8 AND AL,0F8 ; Zero out the irrelevant green bits
00421CC1 8BD8 MOV EBX,EAX
00421CC3 C1EB 05 SHR EBX,5 ; Shift the red MSBs to where the missing red LSBs need to be
00421CC6 09C3 OR EBX,EAX ; The correct conversion result is now in BL
00421CC8 881C3A MOV BYTE PTR DS:[EDX+EDI],BL ; Write the red pixel data
00421CCB 85C9 TEST ECX,ECX ; Are we done here?
00421CCD ^ 75 BD JNZ SHORT Level_Ed.00421C8C
00421CCF 8B5C24 18 MOV EBX,DWORD PTR SS:[ESP+18] ; Pointer to start of target texture pixel data
00421CD3 8B6C24 10 MOV EBP,DWORD PTR SS:[ESP+10] ; Byte width (per row) of the target texture
00421CD7 90 NOP ; The wonders of hand-optimized assembly!
00421CD8 90 NOP

UCyborg
Dragon
Posts: 433
Joined: Sun Jul 07, 2013 7:24 pm
Location: Slovenia

Re: Widescreen hack and some other fixes aka AiO Patch

Post by UCyborg »

So would that be related to the flickering insane corruption that happens when the lightning flashes (even if off-screen) - presumably due to garbage data being written to the z-buffer (in the wrong format)?

No, z-buffer is locked just to be read to determine whether the lens flare in question should be rendered or not. The only thing that happens due to incorrect format is that no flare that should be visible is marked as such.

The screen corruption is caused by the mere action of locking the z-buffer. Perhaps getting depth values without explicitly locking it is the key. I'll experiment with this when I find some time.
"When a human being takes his life in depression, this is a natural death of spiritual causes. The modern barbarity of 'saving' the suicidal is based on a hair-raising misapprehension of the nature of existence." - Peter Wessel Zapffe

UCyborg
Dragon
Posts: 433
Joined: Sun Jul 07, 2013 7:24 pm
Location: Slovenia

Re: Widescreen hack and some other fixes aka AiO Patch

Post by UCyborg »

Small update:

  • Updated lens flare visibility checking code to be able to read 32-bit floating point depth values.
  • Added option to force usage of 32-bit depth mask.
"When a human being takes his life in depression, this is a natural death of spiritual causes. The modern barbarity of 'saving' the suicidal is based on a hair-raising misapprehension of the nature of existence." - Peter Wessel Zapffe

User avatar
Mechanist
Dragon
Posts: 303
Joined: Wed Mar 07, 2018 7:27 pm
Location: Poland

Re: Widescreen hack and some other fixes aka AiO Patch

Post by Mechanist »

Nice, at least there is some progress in the right direction :)

Here's what happens on my system now:
With Force32BitDepthMask=0, everything is exactly the same as before.

With Force32BitDepthMask=1, the lens flare effects now show up regardless of whether dgVoodoo is used or not; it also doesn't matter if antialiasing is forced on via Radeon settings.

However, the problem with the flickering screen corruption (with no antialiasing and no dgVoodoo) still occurs exactly the same as before.
The visual effects of the corruption are the same as before: only Arokh's wings are visible, and random parts of the screen become overwritten with totally unrelated parts of the level geometry (sadly, the latter isn't visible at all well in this screenshot, except for some minor corruption near the top of the screen).
Lens flare stuff.jpg
Lens flare stuff.jpg (94.27 KiB) Viewed 66713 times

-------------------

Also it'd be nice to have some more robust way of programmatically determining whether it should use a 32-bit depth mask or not.

The problem is: from what I've seen, many of the Community Patch users don't use either dgVoodoo or antialiasing. Yes, I know that isn't a good way of doing things, but it's their choice and there isn't much that I can do about it.

Having a .ini file setting that needs to be turned on or off depending on the particulars of the system configuration is a deployment nightmare.
I haven't tested this yet, but I presume that Bad Things will happen if I set Force32BitDepthMask=1 on systems where it needs be set to 0.

There probably exists some obscure way of querying the make and model of the installed graphics card(s) through Inno Setup, but that's just asking for trouble - especially with all the different driver versions floating around out there.

-------------------

The last major changes to the Level Editor for the time being:

First, in the .text section - a simple fix to the texture bitness converter code, which allows it to correctly convert 32-bit textures to 16 bits:
00421BEE |. 83F8 20 CMP EAX,20 ; When converting a 32-bit texture to any other format
00421BF1 |.- 0F84 45B50D00 JE Level_Ed.004FD13C ; Jump to new code that corrects the byte order for that particular case
00421BF7 |. 83F8 10 CMP EAX,10

Then, I removed the code that displayed an error message when trying to export a texture with an integrated alpha map (FLAGS.1 = True), added an extra check for 32-bit textures (regardless of the FLAGS bits), and made it jump to my new code in these cases:
00422FAE |. 8BF9 MOV EDI,ECX
00422FB0 |. 837F 0C 20 CMP DWORD PTR DS:[EDI+C],20 ; Is this a 32-bit texture?
00422FB4 |. 74 08 JE SHORT Level_Ed.00422FBE ; If yes, process it this way, no matter if it has an alpha channel or not
00422FB6 |. 8B47 30 MOV EAX,DWORD PTR DS:[EDI+30] ; Otherwise, we only care about alpha-mapped 16-bit textures here
00422FB9 |. F6C4 02 TEST AH,2 ; FLAGS.1 - Checks if the texture has an integrated alpha map
00422FBC |. 74 1B JE SHORT Level_Ed.00422FD9
00422FBE |> FFB424 A40200>PUSH DWORD PTR SS:[ESP+2A4] ; Pointer to the full path of file to be written to
00422FC5 |. FFB424 A40200>PUSH DWORD PTR SS:[ESP+2A4] ; Handle to the calling window
00422FCC |. E8 A2A10D00 CALL <Level_Ed.AlphaTextureExporter> ; Do things the NEW way
00422FD1 |. E9 D6010000 JMP Level_Ed.004231AC ; Then leave - we're done here.
00422FD6 | 90 NOP ; No more "Can't save bitmap with this texture format" errors!
00422FD7 | 90 NOP
00422FD8 | 90 NOP
00422FD9 |> 33DB XOR EBX,EBX

And of course the new code:
004FD13C 60 PUSHAD ; 32-bit to 16-bit texture format conversion fixer
004FD13D 8B46 24 MOV EAX,DWORD PTR DS:[ESI+24] ; Handle to memory containing the pixel data
004FD140 50 PUSH EAX ; We need a 2nd copy for unlocking the memory later
004FD141 50 PUSH EAX
004FD142 FF15 00614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalLock>] ; Required because it could be either GMEM_FIXED or GMEM_MOVEABLE
004FD148 85C0 TEST EAX,EAX ; Did it work?
004FD14A 75 07 JNZ SHORT Level_Ed.004FD153 ; Bail out if that failed for whatever reason
004FD14C 58 POP EAX
004FD14D 61 POPAD
004FD14E - E9 D44DF2FF JMP Level_Ed.00421F27 ; Return control to the Editor
004FD153 8BF8 MOV EDI,EAX
004FD155 8B4E 04 MOV ECX,DWORD PTR DS:[ESI+4]
004FD158 8B06 MOV EAX,DWORD PTR DS:[ESI]
004FD15A 0FAFC8 IMUL ECX,EAX ; Horizontal width (px) times vertical height (px)
004FD15D 49 DEC ECX ; Start of the byte-flipping loop
004FD15E 8B048F MOV EAX,DWORD PTR DS:[EDI+ECX*4] ; Grab the DWORD
004FD161 0FC8 BSWAP EAX ; Correct the byte order
004FD163 C1C8 08 ROR EAX,8
004FD166 89048F MOV DWORD PTR DS:[EDI+ECX*4],EAX ; Then put it back
004FD169 85C9 TEST ECX,ECX
004FD16B ^ 75 F0 JNZ SHORT Level_Ed.004FD15D
004FD16D FF15 04614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalUnlock>] ; Clean up
004FD173 ^ EB D8 JMP SHORT Level_Ed.004FD14D

004FD176 60 PUSHAD ; function AlphaTextureExporter
004FD177 8BE9 MOV EBP,ECX ; Pointer to the source texture's metadata
004FD179 3E:8B45 24 MOV EAX,DWORD PTR DS:[EBP+24] ; Handle to the source texture's pixel data
004FD17D 50 PUSH EAX ; We need a 2nd copy for unlocking the memory later
004FD17E 50 PUSH EAX
004FD17F FF15 00614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalLock>] ; Convert the handle into a pointer
004FD185 85C0 TEST EAX,EAX ; Did it work?
004FD187 74 35 JE SHORT Level_Ed.004FD1BE ; Bail out if it failed for whatever reason
004FD189 8BF0 MOV ESI,EAX ; Pointer to the source texture's pixel data
004FD18B 3E:8B45 00 MOV EAX,DWORD PTR DS:[EBP] ; Horizontal width of the source texture (px)
004FD18F 3E:8B55 04 MOV EDX,DWORD PTR DS:[EBP+4] ; Vertical height of the source texture (px)
004FD193 0FAFC2 IMUL EAX,EDX ; Number of pixels in the source texture
004FD196 50 PUSH EAX ; Store a copy of the pixel count for later use
004FD197 3E:837D 0C 20 CMP DWORD PTR DS:[EBP+C],20 ; Bits per pixel of the source texture
004FD19C 75 05 JNZ SHORT Level_Ed.004FD1A3 ; If it's not 32-bit, it can only be 16-bit then
004FD19E C1E0 02 SHL EAX,2 ; Correct buffer size for a 32-bit .BMP
004FD1A1 EB 03 JMP SHORT Level_Ed.004FD1A6
004FD1A3 6BC0 03 IMUL EAX,EAX,3 ; Correct buffer size for a 24-bit .BMP
004FD1A6 50 PUSH EAX ; Store a copy of the buffer size for later use
004FD1A7 50 PUSH EAX ; BufferSize
004FD1A8 6A 00 PUSH 0 ; Flags = GMEM_FIXED
004FD1AA FF15 FC604A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalAlloc>] ; Allocate the new temporary pixel data buffer
004FD1B0 85C0 TEST EAX,EAX ; Did it work?
004FD1B2 75 0F JNZ SHORT Level_Ed.004FD1C3
004FD1B4 58 POP EAX ; Clean up
004FD1B5 58 POP EAX
004FD1B6 FF15 04614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalUnlock>] ; kernel32.GlobalUnlock
004FD1BC EB 01 JMP SHORT Level_Ed.004FD1BF
004FD1BE 58 POP EAX
004FD1BF 61 POPAD
004FD1C0 C2 0800 RETN 8 ; Bail out if it didn't
004FD1C3 8BF8 MOV EDI,EAX ; Pointer to the newly allocated memory
004FD1C5 6A 00 PUSH 0 ; hTemplateFile = NULL
004FD1C7 68 80000000 PUSH 80 ; Attributes = NORMAL
004FD1CC 6A 02 PUSH 2 ; Mode = CREATE_ALWAYS
004FD1CE 6A 00 PUSH 0 ; pSecurity = NULL
004FD1D0 6A 02 PUSH 2 ; ShareMode = FILE_SHARE_WRITE
004FD1D2 68 00000040 PUSH 40000000 ; Access = GENERIC_WRITE
004FD1D7 FF7424 4C PUSH DWORD PTR SS:[ESP+4C] ; FileName
004FD1DB FF15 7C614A00 CALL DWORD PTR DS:[<&KERNEL32.CreateFileA>] ; Create the target file
004FD1E1 83F8 FF CMP EAX,-1 ; Did it work?
004FD1E4 75 1C JNZ SHORT Level_Ed.004FD202
004FD1E6 57 PUSH EDI ; Pointer to the recently allocated memory
004FD1E7 FF15 A0614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalFree>] ; Deallocate it for cleanup
004FD1ED 6A 10 PUSH 10
004FD1EF 68 20010000 PUSH 120
004FD1F4 FF7424 38 PUSH DWORD PTR SS:[ESP+38]
004FD1F8 E8 3390F7FF CALL <Level_Ed.MessageWindowDisplayer> ; If the file creation failed, show an error message, then clean up
004FD1FD 83C4 14 ADD ESP,14
004FD200 ^ EB B4 JMP SHORT Level_Ed.004FD1B6 ; And bail out
004FD202 8BD8 MOV EBX,EAX ; Store the file handle for safekeeping
004FD204 3E:837D 0C 20 CMP DWORD PTR DS:[EBP+C],20 ; Bits per pixel of the source texture
004FD209 74 05 JE SHORT Level_Ed.004FD210
004FD20B E9 A0000000 JMP Level_Ed.004FD2B0
004FD210 8B4C24 04 MOV ECX,DWORD PTR SS:[ESP+4] ; Do this if it's a 32-bit texture...
004FD214 49 DEC ECX ; Start of the byte-shifting loop
004FD215 8B048E MOV EAX,DWORD PTR DS:[ESI+ECX*4] ; Grab the source DWORD
004FD218 C1C0 08 ROL EAX,8 ; Adjust the byte placement
004FD21B 89048F MOV DWORD PTR DS:[EDI+ECX*4],EAX ; Write the adjusted DWORD to the target buffer
004FD21E 85C9 TEST ECX,ECX ; Are we done here?
004FD220 ^ 75 F2 JNZ SHORT Level_Ed.004FD214
004FD222 33C0 XOR EAX,EAX
004FD224 33D2 XOR EDX,EDX
004FD226 B2 FF MOV DL,0FF
004FD228 3E:8B4D 10 MOV ECX,DWORD PTR DS:[EBP+10] ; Is this a texture with an alpha channel?
004FD22C E3 03 JECXZ SHORT Level_Ed.004FD231 ; Write the correct BITFIELDS value for the alpha channel (if it exists)
004FD22E 52 PUSH EDX
004FD22F EB 01 JMP SHORT Level_Ed.004FD232
004FD231 50 PUSH EAX
004FD232 C1E2 08 SHL EDX,8
004FD235 52 PUSH EDX
004FD236 C1E2 08 SHL EDX,8
004FD239 52 PUSH EDX
004FD23A C1E2 08 SHL EDX,8
004FD23D 52 PUSH EDX ; More BITFIELDS
004FD23E 50 PUSH EAX ; "Important colors" field (0 = ALL)
004FD23F 50 PUSH EAX ; "Colors used" field (0 = ALL)
004FD240 BA 130B0000 MOV EDX,0B13
004FD245 52 PUSH EDX ; "Y pixels per meter"
004FD246 52 PUSH EDX ; "X pixels per meter"
004FD247 8B5424 20 MOV EDX,DWORD PTR SS:[ESP+20] ; Size of pixel data buffer
004FD24B 52 PUSH EDX ; "ImageSize" field
004FD24C 6A 03 PUSH 3 ; "Compression" (3 = BITFIELDS)
004FD24E 68 01002000 PUSH 200001 ; "Bits per pixel" and "Planes" fields
004FD253 3E:FF75 04 PUSH DWORD PTR DS:[EBP+4] ; Vertical height (px)
004FD257 3E:FF75 00 PUSH DWORD PTR DS:[EBP] ; Horizontal width (px)
004FD25B 6A 38 PUSH 38 ; "Size of InfoHeader"
004FD25D 6A 46 PUSH 46 ; Offset from the start of file to the start of pixel data
004FD25F 50 PUSH EAX ; Unused field
004FD260 83C2 46 ADD EDX,46 ; Size of complete .BMP file
004FD263 52 PUSH EDX
004FD264 68 0000424D PUSH 4D420000 ; "BM" signature
004FD269 8D5424 02 LEA EDX,DWORD PTR SS:[ESP+2] ; Pointer to the beginning of BMP header data on the stack
004FD26D 83EC 04 SUB ESP,4 ; Make space for the BytesWritten return value
004FD270 8D0C24 LEA ECX,DWORD PTR SS:[ESP]
004FD273 50 PUSH EAX ; pOverlapped = NULL
004FD274 51 PUSH ECX ; pBytesWritten
004FD275 6A 46 PUSH 46 ; nBytesToWrite = 46 (70.)
004FD277 52 PUSH EDX ; Buffer
004FD278 53 PUSH EBX ; hFile
004FD279 FF15 80614A00 CALL DWORD PTR DS:[<&KERNEL32.WriteFile>] ; Write the .BMP header data
004FD27F 83C4 48 ADD ESP,48 ; Get rid of the temp buffer
004FD282 8B5424 04 MOV EDX,DWORD PTR SS:[ESP+4] ; Size of buffer to copy
004FD286 8D0C24 LEA ECX,DWORD PTR SS:[ESP]
004FD289 6A 00 PUSH 0 ; pOverlapped = NULL
004FD28B 51 PUSH ECX ; pBytesWritten
004FD28C 52 PUSH EDX ; nBytesToWrite
004FD28D 57 PUSH EDI ; Buffer
004FD28E 53 PUSH EBX ; hFile
004FD28F FF15 80614A00 CALL DWORD PTR DS:[<&KERNEL32.WriteFile>] ; Write the .BMP pixel data
004FD295 53 PUSH EBX ; Handle to the .BMP file being written
004FD296 FF15 84614A00 CALL DWORD PTR DS:[<&KERNEL32.CloseHandle>] ; Close the file - we're done with it now
004FD29C 57 PUSH EDI ; Pointer to the temporary memory buffer
004FD29D FF15 A0614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalFree>] ; Deallocate it for cleanup
004FD2A3 83C4 0C ADD ESP,0C ; Restore the stack pointer to the correct value
004FD2A6 FF15 04614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalUnlock>] ; Unlock the source texture memory buffer
004FD2AC 61 POPAD
004FD2AD C2 0800 RETN 8 ; All done!
004FD2B0 FF3424 PUSH DWORD PTR SS:[ESP] ; Do this if it's a 16-bit texture...
004FD2B3 6A 00 PUSH 0 ; Flags = GMEM_FIXED
004FD2B5 FF15 FC604A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalAlloc>] ; Allocate a 2nd temporary pixel data buffer
004FD2BB 85C0 TEST EAX,EAX ; Did it work?
004FD2BD 75 1A JNZ SHORT Level_Ed.004FD2D9
004FD2BF 53 PUSH EBX ; Clean up and bail out if it didn't
004FD2C0 FF15 84614A00 CALL DWORD PTR DS:[<&KERNEL32.CloseHandle>] ; Close the file - we're done with it
004FD2C6 57 PUSH EDI ; Pointer to the temporary memory buffer
004FD2C7 FF15 A0614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalFree>] ; Deallocate it for cleanup
004FD2CD 58 POP EAX
004FD2CE 58 POP EAX
004FD2CF FF15 04614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalUnlock>] ; Unlock the source texture memory buffer
004FD2D5 61 POPAD
004FD2D6 C2 0800 RETN 8
004FD2D9 50 PUSH EAX ; Store the memory handle for safekeeping
004FD2DA 33C0 XOR EAX,EAX ; Set up the string compare operation
004FD2DC 33C9 XOR ECX,ECX
004FD2DE F7D1 NOT ECX
004FD2E0 56 PUSH ESI
004FD2E1 57 PUSH EDI
004FD2E2 8B7C24 40 MOV EDI,DWORD PTR SS:[ESP+40] ; Pointer to the full path of primary texture .BMP file
004FD2E6 57 PUSH EDI
004FD2E7 F2:AE REPNE SCAS BYTE PTR ES:[EDI]
004FD2E9 5E POP ESI
004FD2EA F7D1 NOT ECX ; Now we have the length of the 0-terminated string in ECX
004FD2EC 8BFC MOV EDI,ESP
004FD2EE 2BF9 SUB EDI,ECX ; Adjust the pointer by the length of our string
004FD2F0 83EF 06 SUB EDI,6 ; Then adjust for the 6 more bytes required
004FD2F3 57 PUSH EDI
004FD2F4 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ; Copy the whole path to the new location
004FD2F6 36:8B47 FC MOV EAX,DWORD PTR SS:[EDI-4] ; The last 4 bytes of the string (incl. the null terminator)
004FD2FA 36:C747 FB 5F41>MOV DWORD PTR SS:[EDI-5],2E415F ; _A.
004FD302 36:8947 FE MOV DWORD PTR SS:[EDI-2],EAX ; Now the filename has '_A' appended to it
004FD306 8BC4 MOV EAX,ESP
004FD308 8B2424 MOV ESP,DWORD PTR SS:[ESP]
004FD30B 50 PUSH EAX ; Store a copy of the previous value of ESP
004FD30C 6A 00 PUSH 0 ; hTemplateFile = NULL
004FD30E 68 80000000 PUSH 80 ; Attributes = NORMAL
004FD313 6A 02 PUSH 2 ; Mode = CREATE_ALWAYS
004FD315 6A 00 PUSH 0 ; pSecurity = NULL
004FD317 6A 02 PUSH 2 ; ShareMode = FILE_SHARE_WRITE
004FD319 68 00000040 PUSH 40000000 ; Access = GENERIC_WRITE
004FD31E 36:FF30 PUSH DWORD PTR SS:[EAX] ; FileName
004FD321 FF15 7C614A00 CALL DWORD PTR DS:[<&KERNEL32.CreateFileA>] ; Open the alpha map .BMP for writing
004FD327 5C POP ESP ; Order on the stack!
004FD328 59 POP ECX
004FD329 5F POP EDI
004FD32A 5E POP ESI
004FD32B 85C0 TEST EAX,EAX ; Did it work?
004FD32D 75 08 JNZ SHORT Level_Ed.004FD337
004FD32F FF15 A0614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalFree>] ; Clean up and bail out if it didn't
004FD335 ^ EB 88 JMP SHORT Level_Ed.004FD2BF
004FD337 50 PUSH EAX ; Store the handle to the alpha map .BMP file for safekeeping
004FD338 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+C] ; Number of pixels in the texture being exported
004FD33C 8B55 10 MOV EDX,DWORD PTR SS:[EBP+10] ; Number of alpha bits per pixel
004FD33F 3E:FF75 04 PUSH DWORD PTR DS:[EBP+4] ; Vertical height (px)
004FD343 3E:FF75 00 PUSH DWORD PTR DS:[EBP] ; Horizontal width (px)
004FD347 8B6C24 0C MOV EBP,DWORD PTR SS:[ESP+C] ; Pointer to the memory buffer for the _A.BMP pixel data
004FD34B 53 PUSH EBX ; Store the handle to the primary texture .BMP file for safekeeping
004FD34C 83FA 01 CMP EDX,1
004FD34F 0F84 C4000000 JE Level_Ed.004FD419
004FD355 83FA 04 CMP EDX,4
004FD358 74 67 JE SHORT Level_Ed.004FD3C1
004FD35A 49 DEC ECX ; If this is 8 alpha bits per pixel...
004FD35B 66:8B144E MOV DX,WORD PTR DS:[ESI+ECX*2] ; Grab the source word
004FD35F 6BC1 03 IMUL EAX,ECX,3 ; Calculate the correct offset for the output pixel data
004FD362 883428 MOV BYTE PTR DS:[EAX+EBP],DH ; Write the alpha bytes verbatim to the output buffer
004FD365 887428 01 MOV BYTE PTR DS:[EAX+EBP+1],DH
004FD369 887428 02 MOV BYTE PTR DS:[EAX+EBP+2],DH
004FD36D 52 PUSH EDX ; Save a copy for later use
004FD36E 52 PUSH EDX ; And a second one too
004FD36F 83E2 03 AND EDX,3 ; Mask off all but the blue bits
004FD372 8BDA MOV EBX,EDX
004FD374 C1E2 02 SHL EDX,2
004FD377 09D3 OR EBX,EDX
004FD379 C1E2 02 SHL EDX,2
004FD37C 09D3 OR EBX,EDX
004FD37E C1E2 02 SHL EDX,2
004FD381 09D3 OR EBX,EDX
004FD383 881C38 MOV BYTE PTR DS:[EAX+EDI],BL ; Write the blue pixel data
004FD386 5A POP EDX
004FD387 C1EA 02 SHR EDX,2 ; Shift out the blue bits
004FD38A 83E2 07 AND EDX,7 ; Mask off all but the green bits
004FD38D 8BDA MOV EBX,EDX
004FD38F C1E2 03 SHL EDX,3
004FD392 09D3 OR EBX,EDX
004FD394 C1E2 03 SHL EDX,3
004FD397 09D3 OR EBX,EDX
004FD399 D1EB SHR EBX,1
004FD39B 885C38 01 MOV BYTE PTR DS:[EAX+EDI+1],BL ; Write the green pixel data
004FD39F 5A POP EDX
004FD3A0 C1EA 05 SHR EDX,5 ; Shift out the blue and green bits
004FD3A3 83E2 07 AND EDX,7 ; Mask off all but the red bits
004FD3A6 8BDA MOV EBX,EDX
004FD3A8 C1E2 03 SHL EDX,3
004FD3AB 09D3 OR EBX,EDX
004FD3AD C1E2 03 SHL EDX,3
004FD3B0 09D3 OR EBX,EDX
004FD3B2 D1EB SHR EBX,1
004FD3B4 885C38 02 MOV BYTE PTR DS:[EAX+EDI+2],BL ; Write the red pixel data
004FD3B8 85C9 TEST ECX,ECX
004FD3BA ^ 75 9E JNZ SHORT Level_Ed.004FD35A
004FD3BC E9 B1000000 JMP Level_Ed.004FD472
004FD3C1 49 DEC ECX ; If this is 4 alpha bits per pixel...
004FD3C2 33D2 XOR EDX,EDX
004FD3C4 66:8B144E MOV DX,WORD PTR DS:[ESI+ECX*2] ; Grab the source word
004FD3C8 6BC1 03 IMUL EAX,ECX,3 ; Calculate the correct offset for the output pixel data
004FD3CB 52 PUSH EDX ; Save 3 copies for later use
004FD3CC 52 PUSH EDX
004FD3CD 52 PUSH EDX
004FD3CE 80E6 F0 AND DH,0F0 ; Mask off everything but the alpha bits
004FD3D1 8BDA MOV EBX,EDX
004FD3D3 C1EA 04 SHR EDX,4
004FD3D6 09D3 OR EBX,EDX
004FD3D8 883C28 MOV BYTE PTR DS:[EAX+EBP],BH ; Write the alpha bytes to the output buffer
004FD3DB 887C28 01 MOV BYTE PTR DS:[EAX+EBP+1],BH
004FD3DF 887C28 02 MOV BYTE PTR DS:[EAX+EBP+2],BH
004FD3E3 5A POP EDX
004FD3E4 83E2 0F AND EDX,0F ; Mask off everything but the blue bits
004FD3E7 8BDA MOV EBX,EDX
004FD3E9 C1E2 04 SHL EDX,4
004FD3EC 09D3 OR EBX,EDX
004FD3EE 881C38 MOV BYTE PTR DS:[EAX+EDI],BL ; Write the blue pixel data
004FD3F1 5A POP EDX
004FD3F2 66:81E2 F000 AND DX,0F0 ; Mask off everything but the green bits
004FD3F7 8BDA MOV EBX,EDX
004FD3F9 C1EA 04 SHR EDX,4
004FD3FC 09D3 OR EBX,EDX
004FD3FE 885C38 01 MOV BYTE PTR DS:[EAX+EDI+1],BL ; Write the green pixel data
004FD402 5A POP EDX
004FD403 66:81E2 000F AND DX,0F00 ; Mask off everything but the red bits
004FD408 8BDA MOV EBX,EDX
004FD40A C1E2 04 SHL EDX,4
004FD40D 09D3 OR EBX,EDX
004FD40F 887C38 02 MOV BYTE PTR DS:[EAX+EDI+2],BH ; Write the red pixel data
004FD413 85C9 TEST ECX,ECX
004FD415 ^ 75 AA JNZ SHORT Level_Ed.004FD3C1
004FD417 EB 59 JMP SHORT Level_Ed.004FD472
004FD419 49 DEC ECX ; If this is 1 alpha bit per pixel...
004FD41A 66:8B144E MOV DX,WORD PTR DS:[ESI+ECX*2] ; Grab the source word
004FD41E 6BC1 03 IMUL EAX,ECX,3 ; Calculate the correct offset for the output pixel data
004FD421 52 PUSH EDX ; Save 2 copies for later use
004FD422 52 PUSH EDX
004FD423 33DB XOR EBX,EBX
004FD425 0FBAE2 0F BT EDX,0F ; Value of the alpha bit
004FD429 73 02 JNB SHORT Level_Ed.004FD42D
004FD42B F7D3 NOT EBX
004FD42D 66:891C28 MOV WORD PTR DS:[EAX+EBP],BX ; Write the alpha bytes to the output buffer
004FD431 885C28 02 MOV BYTE PTR DS:[EAX+EBP+2],BL
004FD435 83E2 1F AND EDX,1F ; Mask off everything but the blue bits
004FD438 8BDA MOV EBX,EDX
004FD43A C1E2 05 SHL EDX,5
004FD43D 09D3 OR EBX,EDX
004FD43F C1EB 02 SHR EBX,2
004FD442 881C38 MOV BYTE PTR DS:[EAX+EDI],BL ; Write the blue pixel data
004FD445 5A POP EDX
004FD446 81E2 E0030000 AND EDX,3E0 ; Mask off all but the green bits
004FD44C 8BDA MOV EBX,EDX
004FD44E C1EA 05 SHR EDX,5
004FD451 09D3 OR EBX,EDX
004FD453 C1EB 02 SHR EBX,2 ; Put the green bits in the right position
004FD456 885C38 01 MOV BYTE PTR DS:[EAX+EDI+1],BL ; Write the green pixel data
004FD45A 5A POP EDX
004FD45B 81E2 007C0000 AND EDX,7C00 ; Mask off all but the red bits
004FD461 8BDA MOV EBX,EDX
004FD463 C1EA 05 SHR EDX,5
004FD466 09D3 OR EBX,EDX
004FD468 D1E3 SHL EBX,1
004FD46A 887C38 02 MOV BYTE PTR DS:[EAX+EDI+2],BH ; Write the red pixel data
004FD46E 85C9 TEST ECX,ECX
004FD470 ^ 75 A7 JNZ SHORT Level_Ed.004FD419
004FD472 8B4424 14 MOV EAX,DWORD PTR SS:[ESP+14] ; Size of the pixel data buffer
004FD476 8B5424 38 MOV EDX,DWORD PTR SS:[ESP+38] ; Pointer to the texture metadata
004FD47A 51 PUSH ECX ; Prepare the .BMP file header
004FD47B 51 PUSH ECX
004FD47C 51 PUSH ECX
004FD47D 51 PUSH ECX
004FD47E 50 PUSH EAX ; Size of the pixel data
004FD47F 51 PUSH ECX ; "Compression" (0 = NONE)
004FD480 68 01001800 PUSH 180001 ; "Bits per pixel" and "Planes" fields
004FD485 FF72 04 PUSH DWORD PTR DS:[EDX+4] ; Vertical height (px)
004FD488 FF32 PUSH DWORD PTR DS:[EDX] ; Horizontal width (px)
004FD48A 6A 28 PUSH 28 ; "Size of InfoHeader"
004FD48C 6A 36 PUSH 36 ; Offset from the start of file to the start of pixel data
004FD48E 51 PUSH ECX ; Unused field
004FD48F 83C0 36 ADD EAX,36 ; Size of complete .BMP file
004FD492 50 PUSH EAX
004FD493 68 0000424D PUSH 4D420000 ; "BM" signature
004FD498 8D5424 02 LEA EDX,DWORD PTR SS:[ESP+2] ; Pointer to the beginning of BMP header data on the stack
004FD49C 83EC 04 SUB ESP,4 ; Make space for the BytesWritten return value
004FD49F 8D1C24 LEA EBX,DWORD PTR SS:[ESP]
004FD4A2 51 PUSH ECX ; pOverlapped = NULL
004FD4A3 53 PUSH EBX ; pBytesWritten
004FD4A4 6A 36 PUSH 36 ; nBytesToWrite = 36 (54.)
004FD4A6 52 PUSH EDX ; Buffer
004FD4A7 FF7424 4C PUSH DWORD PTR SS:[ESP+4C] ; hFile
004FD4AB FF15 80614A00 CALL DWORD PTR DS:[<&KERNEL32.WriteFile>] ; Write the .BMP header data
004FD4B1 6A 00 PUSH 0 ; pOverlapped = NULL
004FD4B3 53 PUSH EBX ; pBytesWritten
004FD4B4 FF7424 58 PUSH DWORD PTR SS:[ESP+58] ; nBytesToWrite
004FD4B8 57 PUSH EDI ; Buffer
004FD4B9 FF7424 4C PUSH DWORD PTR SS:[ESP+4C] ; hFile
004FD4BD FF15 80614A00 CALL DWORD PTR DS:[<&KERNEL32.WriteFile>] ; Write the .BMP pixel data (primary texture)
004FD4C3 FF7424 3C PUSH DWORD PTR SS:[ESP+3C]
004FD4C7 FF15 84614A00 CALL DWORD PTR DS:[<&KERNEL32.CloseHandle>] ; Close the primary texture .BMP file
004FD4CD 57 PUSH EDI
004FD4CE FF15 A0614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalFree>] ; Deallocate the memory formerly occupied by the primary texture pixel data
004FD4D4 8D5424 06 LEA EDX,DWORD PTR SS:[ESP+6] ; Pointer to the beginning of BMP header data on the stack
004FD4D8 6A 00 PUSH 0 ; pOverlapped = NULL
004FD4DA 53 PUSH EBX ; pBytesWritten
004FD4DB 6A 36 PUSH 36 ; nBytesToWrite = 36 (54.)
004FD4DD 52 PUSH EDX ; Buffer
004FD4DE FF7424 58 PUSH DWORD PTR SS:[ESP+58] ; hFile
004FD4E2 FF15 80614A00 CALL DWORD PTR DS:[<&KERNEL32.WriteFile>] ; Write the .BMP header data
004FD4E8 6A 00 PUSH 0 ; pOverlapped = NULL
004FD4EA 53 PUSH EBX ; pBytesWritten
004FD4EB FF7424 58 PUSH DWORD PTR SS:[ESP+58] ; nBytesToWrite
004FD4EF 55 PUSH EBP ; Buffer
004FD4F0 FF7424 58 PUSH DWORD PTR SS:[ESP+58] ; hFile
004FD4F4 FF15 80614A00 CALL DWORD PTR DS:[<&KERNEL32.WriteFile>] ; Write the .BMP pixel data (alpha map)
004FD4FA FF7424 48 PUSH DWORD PTR SS:[ESP+48]
004FD4FE FF15 84614A00 CALL DWORD PTR DS:[<&KERNEL32.CloseHandle>] ; Close the alpha map .BMP file
004FD504 55 PUSH EBP
004FD505 FF15 A0614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalFree>] ; Deallocate the memory formerly occupied by the alpha map pixel data
004FD50B 83C4 58 ADD ESP,58 ; Clean up
004FD50E FF15 04614A00 CALL DWORD PTR DS:[<&KERNEL32.GlobalUnlock>] ; Unlock the source texture memory buffer
004FD514 61 POPAD
004FD515 33C0 XOR EAX,EAX ; Return 0
004FD517 C2 0800 RETN 8
Attachments
Level Editor.zip
(459.17 KiB) Downloaded 1634 times

Post Reply