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 (94.27 KiB) Viewed 104700 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