Skip to content

Commit

Permalink
tr2/decomp: fix windowed screenshots not working
Browse files Browse the repository at this point in the history
Resolves #1766.
  • Loading branch information
rr- committed Oct 27, 2024
1 parent 535a502 commit d944073
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 27 deletions.
1 change: 1 addition & 0 deletions docs/tr2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- fixed Lara's underwater hue being retained when re-entering a boat (#1596)
- fixed Lara reloading the harpoon gun after every shot in NG+ (#1575)
- fixed the dragon reviving itself after Lara removes the dagger in rare circumstances (#1572)
- fixed screenshots not working in windowed mode (#1766)

## [0.5](https://github.com/LostArtefacts/TRX/compare/afaf12a...tr2-0.5) - 2024-10-08
- added `/sfx` command
Expand Down
75 changes: 48 additions & 27 deletions src/tr2/decomp/decomp.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
#include "lib/dinput.h"
#include "specific/s_flagged_string.h"

#include <libtrx/filesystem.h>
#include <libtrx/game/ui/common.h>
#include <libtrx/log.h>
#include <libtrx/memory.h>
#include <libtrx/utils.h>

#include <assert.h>
Expand Down Expand Up @@ -438,15 +441,25 @@ void __cdecl ScreenshotTGA(IDirectDrawSurface3 *screen, int32_t bpp)
return;
}

const int32_t width = desc.dwWidth;
const int32_t height = desc.dwHeight;
const int32_t dst_bpp = bpp == 32 ? 24 : bpp;

int32_t src_x = 0;
int32_t src_y = 0;
int32_t dst_w = desc.dwWidth;
int32_t dst_h = desc.dwHeight;
if (dst_bpp == 24) {
src_x = g_GameWindowPositionX;
src_y = g_GameWindowPositionY;
dst_w = g_GameWindowWidth;
dst_h = g_GameWindowHeight;
}

g_ScreenshotCounter++;

char file_name[20];
sprintf(file_name, "tomb%04d.tga", g_ScreenshotCounter);

FILE *handle = fopen(file_name, "wb");
MYFILE *handle = File_Open(file_name, FILE_OPEN_WRITE);
if (!handle) {
return;
}
Expand All @@ -460,44 +473,45 @@ void __cdecl ScreenshotTGA(IDirectDrawSurface3 *screen, int32_t bpp)
.color_map_depth = 0,
.x_origin = 0,
.y_origin = 0,
.width = width,
.height = height,
.bpp = 16,
.width = dst_w,
.height = dst_h,
.bpp = dst_bpp,
.image_descriptor = 0,
};

fwrite(&header, sizeof(TGA_HEADER), 1, handle);

uint8_t *tga_pic =
(uint8_t *)GlobalAlloc(GMEM_FIXED, width * height * (bpp / 8));
uint8_t *src = desc.lpSurface + desc.lPitch * (height - 1);
File_WriteData(handle, &header, sizeof(TGA_HEADER));

uint8_t *dst = tga_pic;
for (int32_t y = 0; y < height; y++) {
if (desc.ddpfPixelFormat.dwRBitMask == 0xF800) {
// R5G6B5 - transform
for (int32_t x = 0; x < width; x++) {
const uint16_t sample = ((uint16_t *)src)[x];
uint8_t *scanline = Memory_Alloc(dst_w * (dst_bpp / 8));
for (int32_t y = 0; y < dst_h; y++) {
uint8_t *src = desc.lpSurface + desc.lPitch * (dst_h - 1 - (y + src_y));
uint8_t *dst = scanline;
if (bpp == 16 && desc.ddpfPixelFormat.dwRBitMask == 0xF800) {
// R5G6B5 - transform to X1R5G5B5, as TGA reserves the highest bit
for (int32_t x = 0; x < dst_w; x++) {
const uint16_t sample = ((uint16_t *)src)[x + src_x];
((uint16_t *)dst)[x] =
((sample & 0xFFC0) >> 1) | (sample & 0x001F);
}
} else {
} else if (bpp == 16) {
// X1R5G5B5 - good
memcpy(dst, src, sizeof(uint16_t) * width);
memcpy(dst, src + src_x * (bpp / 8), (dst_bpp / 8) * dst_w);
} else if (bpp == 24) {
// RGB24 - good
memcpy(dst, src + src_x * (bpp / 8), (dst_bpp / 8) * dst_w);
} else if (bpp == 32) {
// RGBX - transform to 24-bit, as 32-bit TGA means alpha channel
for (int32_t x = 0; x < dst_w; x++) {
memcpy(dst + x * 3, src + (x + src_x) * 4, 3);
}
}
src -= desc.lPitch;
dst += sizeof(uint16_t) * width;
File_WriteData(handle, scanline, (dst_bpp / 8) * dst_w);
}
fwrite(tga_pic, 2 * height * width, 1, handle);

cleanup:
if (tga_pic) {
GlobalFree(tga_pic);
}
Memory_FreePointer(&scanline);

if (handle) {
fclose(handle);
}
File_Close(handle);
WinVidBufferUnlock(screen, &desc);
}

Expand All @@ -506,12 +520,19 @@ void __cdecl Screenshot(LPDDS screen)
DDSURFACEDESC desc = { 0 };
desc.dwSize = sizeof(DDSURFACEDESC);

LOG_ERROR("Taking screenshot");
if (SUCCEEDED(IDirectDrawSurface_GetSurfaceDesc(screen, &desc))) {
if (desc.ddpfPixelFormat.dwRGBBitCount == 8) {
ScreenshotPCX();
} else if (desc.ddpfPixelFormat.dwRGBBitCount == 16) {
ScreenshotTGA(screen, 16);
} else if (desc.ddpfPixelFormat.dwRGBBitCount == 24) {
ScreenshotTGA(screen, 24);
} else if (desc.ddpfPixelFormat.dwRGBBitCount == 32) {
ScreenshotTGA(screen, 32);
}
} else {
LOG_ERROR("Failed to get surface description: %d", GetLastError());
}
}

Expand Down

0 comments on commit d944073

Please sign in to comment.