OK, the last of my changes to Level Editor.exe for the foreseeable future:
- In the "landscaping tool", the "Brush size" slider has had its sensitivity nerfed by 16x - previously it was impractically huge, with only the first 2 "ticks" being at all useful. This involved changing the opcodes at 484E89 and 00484EA7 from SHL ESI,2 to SHR ESI,2 (no other sliders have been modified).
- Enormously expanded the functionality of "File Import Heights from Bitmap". Description below.
The original "Heights from Bitmap" import functionality is... lackluster... to say the least.
The way it works is that for each layer currently selected, it brings up a dialog to open a .BMP file (must be 8-bit grayscale), and somehow maps these 8 bits of grayscale to 16 bits of the possible layer vertex heights.
Also it has some bizarre scaling properties, since you'd expect that each pixel would preferably map to each vertex
- no, instead it somehow maps each pixel to a tile
, which makes no sense whatsoever.
Needless to say, the functionality it offers is largely crippled and has a very limited range of practically feasible uses.
I needed to expand on that for the map I'm working on - so I wrote a DLL (DEM.dll) that does what I want, and modified the Editor's code to have this DLL loaded on demand.
Now if no layers are selected as the height import target, it launches my DLL, which processes all
of the currently visible floor layers.
The DLL has only 1 exported function that contains all the logic, and takes 2 parameters: handle to the Editor's window, and pointer to the struct that holds information about all the layers.
My DLL reads and writes directly from/to the Editor's memory; the Editor's code is only responsible for checking if the conditions for the DLL's invocation have been met, invoke it with these 2 parameters, then unload it again immediately after it finishes doing its thing.
First, the change to the Editor's existing code for handling the "Heights from Bitmap" OnClick event:
0043178E 7E 35 JLE SHORT Level_Ed.004317C5
00431790 55 PUSH EBP
00431791 33ED XOR EBP,EBP
00431793 8B46 14 MOV EAX,DWORD PTR DS:[ESI+14]
00431796 8B0CB8 MOV ECX,DWORD PTR DS:[EAX+EDI*4]
00431799 8B51 08 MOV EDX,DWORD PTR DS:[ECX+8]
0043179C F6C2 01 TEST DL,1 ; Check if layer is selected for editing
0043179F 74 15 JE SHORT Level_Ed.004317B6
004317A1 F6C2 02 TEST DL,2 ; Check if layer is hidden
004317A4 75 10 JNZ SHORT Level_Ed.004317B6
004317A6 FF7424 14 PUSH DWORD PTR SS:[ESP+14]
004317AA E8 C14B0000 CALL Level_Ed.00436370
004317AF 08C3 OR BL,AL
004317B1 C646 2C 01 MOV BYTE PTR DS:[ESI+2C],1
004317B5 45 INC EBP
004317B6 47 INC EDI
004317B7 3B7E 1C CMP EDI,DWORD PTR DS:[ESI+1C]
004317BA ^ 7C D7 JL SHORT Level_Ed.00431793
004317BC 85ED TEST EBP,EBP
004317BE - 0F84 57BD0C00 JE Level_Ed.004FD51B ; Jump to the new code if no layers have been processed here
004317C4 5D POP EBP
004317C5 8BCE MOV ECX,ESI
004317C7 E8 640D0000 CALL Level_Ed.00432530
004317CC 8BCE MOV ECX,ESI
004317CE E8 7D090000 CALL Level_Ed.00432150
004317D3 5F POP EDI
004317D4 8AC3 MOV AL,BL
004317D6 5E POP ESI
004317D7 5B POP EBX
004317D8 C2 0400 RETN 4
Then the actual new code that deals with the DLL invocation:
004FD51B 33FF XOR EDI,EDI ; This point can only be reached if NO layers were both selected AND visible at the same time
004FD51D 8B46 14 MOV EAX,DWORD PTR DS:[ESI+14] ; But it's also possible that ALL the layers were hidden
004FD520 8B0CB8 MOV ECX,DWORD PTR DS:[EAX+EDI*4] ; That's a pathological case, in which the importer has nothing to do anyway
004FD523 F641 08 02 TEST BYTE PTR DS:[ECX+8],2
004FD527 74 01 JE SHORT Level_Ed.004FD52A
004FD529 45 INC EBP ; EBP = always 0 at the start of this loop
004FD52A 47 INC EDI
004FD52B 3B7E 1C CMP EDI,DWORD PTR DS:[ESI+1C] ; Check ALL the layers!
004FD52E ^ 75 ED JNZ SHORT Level_Ed.004FD51D
004FD530 3BFD CMP EDI,EBP ; Won't be equal if at least 1 layer wasn't hidden
004FD532 75 05 JNZ SHORT Level_Ed.004FD539
004FD534 - E9 8B42F3FF JMP Level_Ed.004317C4 ; Bail out if all the layers were hidden
004FD539 68 44494D00 PUSH Level_Ed.004D4944 ; "DIM"
004FD53E 68 44454D00 PUSH Level_Ed.004D4544 ; "DEM"
004FD543 54 PUSH ESP
004FD544 FF15 54614A00 CALL DWORD PTR DS:[<&KERNEL32.LoadLibrar>; kernel32.LoadLibraryA
004FD54A 85C0 TEST EAX,EAX ; Did it work?
004FD54C 74 20 JE SHORT Level_Ed.004FD56E ; Bail out if it didn't
004FD54E 8BF8 MOV EDI,EAX
004FD550 58 POP EAX
004FD551 54 PUSH ESP
004FD552 57 PUSH EDI
004FD553 FF15 58614A00 CALL DWORD PTR DS:[<&KERNEL32.GetProcAdd>; kernel32.GetProcAddress
004FD559 85C0 TEST EAX,EAX ; Did it work?
004FD55B 74 12 JE SHORT Level_Ed.004FD56F ; Bail out if it didn't
004FD55D 59 POP ECX
004FD55E 56 PUSH ESI ; Pointer to the layer meta-metadata struct
004FD55F FF7424 18 PUSH DWORD PTR SS:[ESP+18] ; Handle to the calling window
004FD563 FFD0 CALL EAX ; Call the one and only export of the DEM importer DLL
004FD565 57 PUSH EDI
004FD566 FF15 5C614A00 CALL DWORD PTR DS:[<&KERNEL32.FreeLibrar>; kernel32.FreeLibrary
004FD56C EB 02 JMP SHORT Level_Ed.004FD570
004FD56E 59 POP ECX
004FD56F 59 POP ECX
004FD570 - E9 4F42F3FF JMP Level_Ed.004317C4 ; Return control back to the Editor
since, as I said, I won't be making any further changes to the Editor anytime soon, feel free to incorporate the modified version into your AiO patch - especially since without it, it's not possible to import and use 32-bit textures, which are now otherwise fully functional.
The only minor snag in the current version is that the form created by my .DLL is supposed to be modal: it shouldn't be possible to even bring the Editor's window into focus, but it is.
It's still largely nonfunctional (because its code execution is stuck on waiting for my DLL to close), but it's nonetheless possible to bring it into focus and click the buttons.
I haven't tracked this issue down yet, since I was primarily focused on getting the import functionality to work in the first place. Now that I'm essentially done with it, I'll try to look into it when time permits.
I've also included the current "alpha build" of my DEM.dll - it's strictly optional to include it; it's not required for the Editor to work.
The DLL only gets loaded when "Heights from Bitmap" is clicked without any layers having been selected
, and even then the code is intended to fail silently if the DLL is missing or corrupt ("You click the button! Nothing happens!").
It should go without saying, but the DEM.dll needs to go in the same folder as the Editor's executable.
Things remaining on the todo list:
- Compile a changelog for the Level Editor + readme explaining the new texture-related functionality,
- Write a readme for the DEM importer,
- Test the DEM importer extensively in an actual usage scenario,
- Polish up the DEM importer (eg. add hover hints and some context help),
- Compile an illustrated guide explaining the whole DEM import process, starting with obtaining the source data.